packages feed

hercules-ci-cnix-expr 0.3.3.0 → 0.3.4.0

raw patch · 6 files changed

+121/−11 lines, 6 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Hercules.CNix.Expr: instance Hercules.CNix.Expr.FromValue Hercules.CNix.Expr.Typed.NixInt GHC.Int.Int64
+ Hercules.CNix.Expr: instance Hercules.CNix.Expr.FromValue Hercules.CNix.Expr.Typed.NixList [Hercules.CNix.Expr.Raw.RawValue]
+ Hercules.CNix.Expr.Schema: (#??) :: (KnownSymbol s, (as ? s) ~ (Null |. b), PossibleTypesForSchema b, MonadEval m) => PSObject (Attrs' as w) -> AttrLabel s -> m (Maybe (PSObject b))
+ Hercules.CNix.Expr.Schema: InvalidValue :: Provenance -> Text -> NixException
+ Hercules.CNix.Expr.Schema: ListItem :: Provenance -> Int -> Provenance
+ Hercules.CNix.Expr.Schema: instance Hercules.CNix.Expr.Schema.FromPSObject GHC.Int.Int64 GHC.Int.Int64
+ Hercules.CNix.Expr.Schema: instance Hercules.CNix.Expr.Schema.FromPSObject a b => Hercules.CNix.Expr.Schema.FromPSObject [a] [b]
+ Hercules.CNix.Expr.Schema: instance Hercules.CNix.Expr.Schema.PossibleTypesForSchema ()
+ Hercules.CNix.Expr.Schema: instance Hercules.CNix.Expr.Schema.PossibleTypesForSchema [a]
+ Hercules.CNix.Expr.Schema: traverseArray :: MonadEval m => (PSObject a -> m b) -> PSObject [a] -> m [b]
+ Hercules.CNix.Expr.Schema: type as ? s = OptionalAttrType' as as s
+ Hercules.CNix.Expr.Typed: getInt :: Value NixInt -> IO Int64
+ Hercules.CNix.Expr.Typed: instance Hercules.CNix.Expr.Typed.HasRawValueType ()
- Hercules.CNix.Expr.Schema: (#.) :: (KnownSymbol s, AttrType as s ~ b, MonadEval m) => PSObject (Attrs' as w) -> AttrLabel s -> m (PSObject b)
+ Hercules.CNix.Expr.Schema: (#.) :: (KnownSymbol s, (as . s) ~ b, MonadEval m) => PSObject (Attrs' as w) -> AttrLabel s -> m (PSObject b)
- Hercules.CNix.Expr.Schema: (#?!) :: (KnownSymbol s, OptionalAttrType as s ~ b, MonadEval m) => PSObject (Attrs' as w) -> AttrLabel s -> m (PSObject b)
+ Hercules.CNix.Expr.Schema: (#?!) :: (KnownSymbol s, (as ? s) ~ b, MonadEval m) => PSObject (Attrs' as w) -> AttrLabel s -> m (PSObject b)
- Hercules.CNix.Expr.Schema: (#?) :: (KnownSymbol s, OptionalAttrType as s ~ b, MonadEval m) => PSObject (Attrs' as w) -> AttrLabel s -> m (Maybe (PSObject b))
+ Hercules.CNix.Expr.Schema: (#?) :: (KnownSymbol s, (as ? s) ~ b, MonadEval m) => PSObject (Attrs' as w) -> AttrLabel s -> m (Maybe (PSObject b))
- Hercules.CNix.Expr.Schema: (>>.) :: (KnownSymbol s, AttrType as s ~ b, MonadEval m) => m (PSObject (Attrs' as w)) -> AttrLabel s -> m (PSObject b)
+ Hercules.CNix.Expr.Schema: (>>.) :: (KnownSymbol s, (as . s) ~ b, MonadEval m) => m (PSObject (Attrs' as w)) -> AttrLabel s -> m (PSObject b)
- Hercules.CNix.Expr.Schema: (>>?) :: (KnownSymbol s, OptionalAttrType as s ~ b, MonadEval m) => m (PSObject (Attrs' as w)) -> AttrLabel s -> m (Maybe (PSObject b))
+ Hercules.CNix.Expr.Schema: (>>?) :: (KnownSymbol s, (as ? s) ~ b, MonadEval m) => m (PSObject (Attrs' as w)) -> AttrLabel s -> m (Maybe (PSObject b))
- Hercules.CNix.Expr.Schema: type a ::? b = a :? b
+ Hercules.CNix.Expr.Schema: type a ::?? b = a :? Null |. b

Files

CHANGELOG.md view
@@ -5,7 +5,20 @@  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). -## 0.3.3.0 - 2022-05-21+## 0.3.4.0 - 2022-11-15++### Added++ - `::??`, `#??` for redundantly optional types: unset or null+ - Schema module instances for `()` representing `null`+ - `InvalidValue` constructor for `NixException`+ - `.` and `?` type operators for field access and optional field access+ - Schema module instances for `[a]` for Nix lists of `a`,+ - Schema `Int64` (= `NixInt`) instance for Nix integers+ - Schema `traverseArray` helper for traversing Nix lists (should have been renamed)+++## 0.3.3.0 - 2022-06-21  ### Added 
hercules-ci-cnix-expr.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.4  name:           hercules-ci-cnix-expr-version:        0.3.3.0+version:        0.3.4.0 synopsis:       Bindings for the Nix evaluator category:       Nix, CI, Testing, DevOps homepage:       https://docs.hercules-ci.com
src/Hercules/CNix/Expr.hs view
@@ -8,6 +8,9 @@ {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-}+#ifdef __GHCIDE__+# define NIX_IS_AT_LEAST(mm,m,p) 1+#endif  module Hercules.CNix.Expr   ( init,@@ -564,6 +567,12 @@  instance FromValue Bool Bool where   fromValue = getBool++instance FromValue NixList [RawValue] where+  fromValue = getList++instance FromValue NixInt Int64 where+  fromValue = getInt  -- | Identity instance ToRawValue RawValue where
src/Hercules/CNix/Expr/Schema.hs view
@@ -48,9 +48,12 @@     -- * Attribute sets as records     type Attrs,     type (::.),+    type (.),     (#.),     (>>.),     type (::?),+    type (::??),+    type (?),     (#?),     (>>?),     (#?!),@@ -77,6 +80,8 @@     -- * Utilities     uncheckedCast,     englishOr,+    traverseArray,+    (#??),   ) where @@ -84,7 +89,7 @@ import qualified Data.Map as M import qualified Data.Text as T import qualified GHC.TypeLits as TL-import Hercules.CNix.Expr (CheckType, EvalState, HasRawValueType, NixAttrs, NixFunction, NixPath, NixString, RawValue, ToRawValue (..), ToValue (..), Value (rtValue), apply, checkType, getAttr, getRawValueType, getStringIgnoreContext, hasContext, rawValueType, toRawValue, valueFromExpressionString)+import Hercules.CNix.Expr (CheckType, EvalState, HasRawValueType, NixAttrs, NixFunction, NixList, NixPath, NixString, RawValue, ToRawValue (..), ToValue (..), Value (rtValue), apply, checkType, getAttr, getRawValueType, getStringIgnoreContext, hasContext, rawValueType, toRawValue, valueFromExpressionString) import qualified Hercules.CNix.Expr as Expr import Hercules.CNix.Expr.Raw (RawValueType, canonicalRawType) import Protolude hiding (TypeError, check, evalState)@@ -95,6 +100,7 @@   | Other Text   | Data   | Attribute Provenance Text+  | ListItem Provenance Int   | Application Provenance Provenance   deriving (Show, Eq, Ord) @@ -108,6 +114,7 @@       -- ^ expected   | InvalidText Provenance UnicodeException   | StringContextNotAllowed Provenance+  | InvalidValue Provenance Text   deriving (Show, Eq)  instance Exception NixException where@@ -115,9 +122,11 @@   displayException (TypeError p actual expected) = "Expecting a value of type " <> toS (englishOr (map show expected)) <> ", but got type " <> show actual <> "." <> appendProvenance p   displayException (InvalidText p ue) = displayException ue <> appendProvenance p   displayException (StringContextNotAllowed p) = "This string must not have a context. It must be usable without building store paths." <> appendProvenance p+  displayException (InvalidValue p msg) = "Invalid value. " <> toS msg <> appendProvenance p  appendProvenance :: Provenance -> [Char] appendProvenance (Attribute p name) = "\n  in attribute " <> show name <> appendProvenance p+appendProvenance (ListItem p index) = "\n  in list item " <> show index <> appendProvenance p appendProvenance (Other x) = "\n  in " <> toS x appendProvenance Data = "" appendProvenance (Application p _p) = "\n  in function result" <> appendProvenance p@@ -136,6 +145,9 @@  infixr 1 ->? +-- | A Nix @null@ value has 1 possible value, like Haskell's @()@.+type Null = ()+ -- | Attribute set schema with known attributes and wildcard type for remaining attributes. data Attrs' (as :: [Attr]) w @@ -168,6 +180,12 @@ -- distinct from an attribute that may be @null@. type a ::? b = a ':? b +-- | Optional (@_?@) attribute name and type (@::_@)+--+-- This indicates that the attribute may be omitted in its entirety, which is+-- distinct from an attribute that may be @null@.+type a ::?? b = a ':? Null |. b+ -- | Required (@_.@) attribute name and type (@::_@) -- -- Note that the type may still be nullable, but the attribute is expected to exist.@@ -207,7 +225,7 @@         value = v       } -type AttrType as s = AttrType' as as s+type as . s = AttrType' as as s  type family AttrType' all as s where   AttrType' all ((s ':. t) ': as) s = t@@ -223,7 +241,7 @@           'TL.:$$: 'TL.Text "  Known attributes are " 'TL.:<>: 'TL.ShowType all       ) -type OptionalAttrType as s = OptionalAttrType' as as s+type as ? s = OptionalAttrType' as as s  type family OptionalAttrType' all as s where   OptionalAttrType' all ((s ':? t) ': as) s = t@@ -252,11 +270,11 @@ type MonadEval m = (MonadIO m, MonadReader (Ptr EvalState) m)  -- | A combination of '>>=' and '#.'.-(>>.) :: (KnownSymbol s, AttrType as s ~ b, MonadEval m) => m (PSObject (Attrs' as w)) -> AttrLabel s -> m (PSObject b)+(>>.) :: (KnownSymbol s, as . s ~ b, MonadEval m) => m (PSObject (Attrs' as w)) -> AttrLabel s -> m (PSObject b) mas >>. p = mas >>= \as -> as #. p  -- | Attribute selector. @a #. #b@ is @a.b@ in Nix. Operates on attributes that are required (@_.@) in the schema, throwing an error if necessary.-(#.) :: (KnownSymbol s, AttrType as s ~ b, MonadEval m) => PSObject (Attrs' as w) -> AttrLabel s -> m (PSObject b)+(#.) :: (KnownSymbol s, as . s ~ b, MonadEval m) => PSObject (Attrs' as w) -> AttrLabel s -> m (PSObject b) as #. p = do   evalState <- ask   let name = T.pack (symbolVal p)@@ -266,11 +284,11 @@     Just b -> pure PSObject {value = b, provenance = Attribute (provenance as) name}  -- | A combination of '>>=' and '#?'.-(>>?) :: (KnownSymbol s, OptionalAttrType as s ~ b, MonadEval m) => m (PSObject (Attrs' as w)) -> AttrLabel s -> m (Maybe (PSObject b))+(>>?) :: (KnownSymbol s, as ? s ~ b, MonadEval m) => m (PSObject (Attrs' as w)) -> AttrLabel s -> m (Maybe (PSObject b)) mas >>? p = mas >>= \as -> as #? p  -- | Attribute selector. @a #? #b@ is @a.b@ in Nix, but handles the missing case without exception. Operates on attributes that are optional (@_?@) in the schema, throwing an error if necessary.-(#?) :: (KnownSymbol s, OptionalAttrType as s ~ b, MonadEval m) => PSObject (Attrs' as w) -> AttrLabel s -> m (Maybe (PSObject b))+(#?) :: (KnownSymbol s, as ? s ~ b, MonadEval m) => PSObject (Attrs' as w) -> AttrLabel s -> m (Maybe (PSObject b)) as #? p = do   evalState <- ask   let name = T.pack (symbolVal p)@@ -278,11 +296,17 @@   liftIO (getAttr evalState v (encodeUtf8 name))     <&> fmap (\b -> PSObject {value = b, provenance = Attribute (provenance as) name}) +-- | Attribute selector. @a #? #b@ is @a.b@ in Nix, but handles the missing case and the null case without exception. Operates on attributes that are optional (@_?@) and nullable (@Null |.@, @() |.@) in the schema.+(#??) :: (KnownSymbol s, as ? s ~ (Null |. b), PossibleTypesForSchema b, MonadEval m) => PSObject (Attrs' as w) -> AttrLabel s -> m (Maybe (PSObject b))+as #?? p = do+  mv <- as #? p+  join <$> for mv (const (pure Nothing) |! (pure . Just))+ -- | Retrieve an optional attribute but throw if it's missing. -- -- It provides a decent error message with attrset provenance, but can't provide -- extra context like you can when manually handling the @a '#?' b@ 'Nothing' case.-(#?!) :: (KnownSymbol s, OptionalAttrType as s ~ b, MonadEval m) => PSObject (Attrs' as w) -> AttrLabel s -> m (PSObject b)+(#?!) :: (KnownSymbol s, as ? s ~ b, MonadEval m) => PSObject (Attrs' as w) -> AttrLabel s -> m (PSObject b) as #?! p = do   as #? p >>= \case     Nothing -> throwIO $ MissingAttribute (provenance as) (T.pack (symbolVal p))@@ -333,6 +357,8 @@   NixTypeForSchema NixPath = NixPath   NixTypeForSchema Bool = Bool   NixTypeForSchema Int64 = Int64+  NixTypeForSchema [a] = NixList+  NixTypeForSchema () = ()  class PossibleTypesForSchema s where   typesForSchema :: Proxy s -> [RawValueType]@@ -351,6 +377,11 @@  instance PossibleTypesForSchema Int64 +instance PossibleTypesForSchema ()++instance PossibleTypesForSchema [a] where+  typesForSchema _ = [getRawValueType (Proxy @NixList)]+ instance   (PossibleTypesForSchema a, PossibleTypesForSchema b) =>   PossibleTypesForSchema (a |. b)@@ -524,3 +555,19 @@  basicAttrsWithProvenance :: Value NixAttrs -> Provenance -> PSObject (Attrs '[]) basicAttrsWithProvenance attrs p = PSObject {value = rtValue attrs, provenance = p}++instance FromPSObject Int64 Int64 where+  fromPSObject o = do+    v <- check o+    liftIO (Expr.fromValue v)++instance forall a b. FromPSObject a b => FromPSObject [a] [b] where+  fromPSObject o = do+    traverseArray fromPSObject o++traverseArray :: (MonadEval m) => (PSObject a -> m b) -> PSObject [a] -> m [b]+traverseArray f o = do+  ov <- check o+  l <- liftIO (Expr.fromValue ov)+  l & zip [0 ..] & traverse \(i, a) ->+    f (PSObject (ListItem (provenance o) i) a :: PSObject a)
src/Hercules/CNix/Expr/Typed.hs view
@@ -19,6 +19,7 @@     match,     match',     getBool,+    getInt,     getStringIgnoreContext,     hasContext,     CheckType (..),@@ -152,6 +153,10 @@   (0 /=)     <$> [C.exp| int { $(Value *v)->boolean ? 1 : 0 }|] +getInt :: Value NixInt -> IO Int64+getInt (Value (RawValue v)) =+  [C.exp| int64_t { $(Value *v)->integer }|]+ -- NOT coerceToString getStringIgnoreContext :: Value NixString -> IO ByteString getStringIgnoreContext (Value (RawValue v)) =@@ -230,3 +235,6 @@  instance HasRawValueType NixList where   getRawValueType _ = List++instance HasRawValueType () where+  getRawValueType _ = Null
test/Hercules/CNix/Expr/SchemaSpec.hs view
@@ -8,6 +8,7 @@ import qualified Hercules.CNix.Expr as Expr import Hercules.CNix.Expr.Raw (RawValueType (Attrs, Bool, Lambda, Null, String)) import Hercules.CNix.Expr.Schema+import Hercules.CNix.Expr.Schema (FromPSObject (fromPSObject)) import Protolude hiding (TypeError, check, evalState) import SingleState (evalState) import Test.Hspec@@ -112,7 +113,8 @@         Proxy           @( Attrs                '[ "optionallyFunction" ::. (NixString ->? NixString),-                  "optionalAttr" ::? NixString+                  "optionalAttr" ::? NixString,+                  "nullableAttr" ::?? [StringWithoutContext]                 ]            ) @@ -169,6 +171,37 @@             schema         e #? #optionalAttr >>= traverse getByteString_       r `shouldBe` Just "nice"++  describe ".#??" do+    it "can return Nothing for unset" \_ -> do+      r <- runES do+        e <-+          exprWithBasePath+            "{ }"+            "/"+            schema+        e #?? #nullableAttr >>= traverse fromPSObject+      r `shouldBe` (Nothing :: Maybe [ByteString])++    it "can return Nothing for null" \_ -> do+      r <- runES do+        e <-+          exprWithBasePath+            "{ nullableAttr = null; }"+            "/"+            schema+        e #?? #nullableAttr >>= traverse fromPSObject+      r `shouldBe` (Nothing :: Maybe [ByteString])++    it "can return Just" \_ -> do+      r <- runES do+        e <-+          exprWithBasePath+            "{ nullableAttr = [''nice'']; }"+            "/"+            schema+        e #?? #nullableAttr >>= traverse fromPSObject+      r `shouldBe` Just ["nice" :: ByteString]    describe "fromPSObject" do     describe "@Bool" do