diff --git a/ogma-cli/CHANGELOG.md b/ogma-cli/CHANGELOG.md index fc5f1c7..4e43a58 100644 --- a/ogma-cli/CHANGELOG.md +++ b/ogma-cli/CHANGELOG.md @@ -1,6 +1,6 @@ # Revision history for ogma-cli -## [1.X.Y] - 2025-02-08 +## [1.X.Y] - 2025-02-09 * Add all auxiliary test files to distributable Cabal package (#216). * Remove extraneous EOL character (#224). @@ -13,6 +13,7 @@ * Update README with new ROS template variables (#244). * Update README with new FPrime template variables (#246). * Adjust CLI to match new backend API (#248). +* Expose template-vars argument to ROS, FPrime, standalone backends (#250). ## [1.6.0] - 2025-01-21 diff --git a/ogma-cli/README.md b/ogma-cli/README.md index 02b1c59..1c1134c 100644 --- a/ogma-cli/README.md +++ b/ogma-cli/README.md @@ -282,6 +282,8 @@ be made available to the monitor. and the topic they are included with. - `--handlers FILENAME`: a file containing a list of handlers used in the specification. +- `--template-vars FILENAME`: a JSON file containing a list of additional + variables to expand in the template. The following execution generates an initial ROS application for runtime monitoring using Copilot: @@ -405,6 +407,8 @@ be made available to the monitor. and their types. - `--handlers FILENAME`: a file containing a list of handlers used in the specification. +- `--template-vars FILENAME`: a JSON file containing a list of additional + variables to expand in the template. The following execution generates an initial F' component for runtime monitoring using Copilot: diff --git a/ogma-cli/src/CLI/CommandFPrimeApp.hs b/ogma-cli/src/CLI/CommandFPrimeApp.hs index 1f9162a..40800dd 100644 --- a/ogma-cli/src/CLI/CommandFPrimeApp.hs +++ b/ogma-cli/src/CLI/CommandFPrimeApp.hs @@ -57,15 +57,16 @@ import qualified Command.FPrimeApp -- | Options needed to generate the FPrime component. data CommandOpts = CommandOpts - { fprimeAppInputFile :: Maybe String - , fprimeAppTarget :: String - , fprimeAppTemplateDir :: Maybe String - , fprimeAppVariables :: Maybe String - , fprimeAppVarDB :: Maybe String - , fprimeAppHandlers :: Maybe String - , fprimeAppFormat :: String - , fprimeAppPropFormat :: String - , fprimeAppPropVia :: Maybe String + { fprimeAppInputFile :: Maybe String + , fprimeAppTarget :: String + , fprimeAppTemplateDir :: Maybe String + , fprimeAppVariables :: Maybe String + , fprimeAppVarDB :: Maybe String + , fprimeAppHandlers :: Maybe String + , fprimeAppFormat :: String + , fprimeAppPropFormat :: String + , fprimeAppPropVia :: Maybe String + , fprimeAppTemplateVars :: Maybe String } -- | Create component that subscribe @@ -87,6 +88,7 @@ command c = Command.FPrimeApp.command options , Command.FPrimeApp.commandFormat = fprimeAppFormat c , Command.FPrimeApp.commandPropFormat = fprimeAppPropFormat c , Command.FPrimeApp.commandPropVia = fprimeAppPropVia c + , Command.FPrimeApp.commandExtraVars = fprimeAppTemplateVars c } -- * CLI @@ -164,6 +166,13 @@ commandOptsParser = CommandOpts <> help strFPrimeAppPropViaDesc ) ) + <*> optional + ( strOption + ( long "template-vars" + <> metavar "FILENAME" + <> help strFPrimeAppTemplateVarsArgDesc + ) + ) -- | Argument target directory to FPrime component generation command strFPrimeAppDirArgDesc :: String @@ -206,3 +215,8 @@ strFPrimeAppPropFormatDesc = "Format of temporal or boolean properties" strFPrimeAppPropViaDesc :: String strFPrimeAppPropViaDesc = "Command to pre-process individual properties" + +-- | Additional template variable file flag description. +strFPrimeAppTemplateVarsArgDesc :: String +strFPrimeAppTemplateVarsArgDesc = + "JSON file containing additional variables to expand in template" diff --git a/ogma-cli/src/CLI/CommandROSApp.hs b/ogma-cli/src/CLI/CommandROSApp.hs index 3c010b7..45051b5 100644 --- a/ogma-cli/src/CLI/CommandROSApp.hs +++ b/ogma-cli/src/CLI/CommandROSApp.hs @@ -57,15 +57,16 @@ import qualified Command.ROSApp -- | Options needed to generate the ROS application. data CommandOpts = CommandOpts - { rosAppInputFile :: Maybe String - , rosAppTarget :: String - , rosAppTemplateDir :: Maybe String - , rosAppVarNames :: Maybe String - , rosAppVarDB :: Maybe String - , rosAppHandlers :: Maybe String - , rosAppFormat :: String - , rosAppPropFormat :: String - , rosAppPropVia :: Maybe String + { rosAppInputFile :: Maybe String + , rosAppTarget :: String + , rosAppTemplateDir :: Maybe String + , rosAppVarNames :: Maybe String + , rosAppVarDB :: Maybe String + , rosAppHandlers :: Maybe String + , rosAppFormat :: String + , rosAppPropFormat :: String + , rosAppPropVia :: Maybe String + , rosAppTemplateVars :: Maybe String } -- | Create (ROS) applications @@ -86,6 +87,7 @@ command c = Command.ROSApp.command options , Command.ROSApp.commandFormat = rosAppFormat c , Command.ROSApp.commandPropFormat = rosAppPropFormat c , Command.ROSApp.commandPropVia = rosAppPropVia c + , Command.ROSApp.commandExtraVars = rosAppTemplateVars c } -- * CLI @@ -163,6 +165,13 @@ commandOptsParser = CommandOpts <> help strROSAppPropViaDesc ) ) + <*> optional + ( strOption + ( long "template-vars" + <> metavar "FILENAME" + <> help strROSAppTemplateVarsArgDesc + ) + ) -- | Argument target directory to ROS app generation command strROSAppDirArgDesc :: String @@ -205,3 +214,8 @@ strROSAppPropFormatDesc = "Format of temporal or boolean properties" strROSAppPropViaDesc :: String strROSAppPropViaDesc = "Command to pre-process individual properties" + +-- | Additional template variable file flag description. +strROSAppTemplateVarsArgDesc :: String +strROSAppTemplateVarsArgDesc = + "JSON file containing additional variables to expand in template" diff --git a/ogma-cli/src/CLI/CommandStandalone.hs b/ogma-cli/src/CLI/CommandStandalone.hs index 070d76f..1b86f79 100644 --- a/ogma-cli/src/CLI/CommandStandalone.hs +++ b/ogma-cli/src/CLI/CommandStandalone.hs @@ -58,14 +58,15 @@ import qualified Command.Standalone -- | Options to generate Copilot from specification. data CommandOpts = CommandOpts - { standaloneTargetDir :: FilePath - , standaloneTemplateDir :: Maybe FilePath - , standaloneFileName :: FilePath - , standaloneFormat :: String - , standalonePropFormat :: String - , standaloneTypes :: [String] - , standaloneTarget :: String - , standalonePropVia :: Maybe String + { standaloneTargetDir :: FilePath + , standaloneTemplateDir :: Maybe FilePath + , standaloneFileName :: FilePath + , standaloneFormat :: String + , standalonePropFormat :: String + , standaloneTypes :: [String] + , standaloneTarget :: String + , standalonePropVia :: Maybe String + , standaloneTemplateVars :: Maybe String } -- | Transform an input specification into a Copilot specification. @@ -83,6 +84,7 @@ command c = , Command.Standalone.commandTypeMapping = types , Command.Standalone.commandFilename = standaloneTarget c , Command.Standalone.commandPropVia = standalonePropVia c + , Command.Standalone.commandExtraVars = standaloneTemplateVars c } types :: [(String, String)] @@ -161,6 +163,13 @@ commandOptsParser = CommandOpts <> help strStandalonePropViaDesc ) ) + <*> optional + ( strOption + ( long "template-vars" + <> metavar "FILENAME" + <> help strStandaloneTemplateVarsArgDesc + ) + ) -- | Target dir flag description. strStandaloneTargetDirDesc :: String @@ -195,3 +204,8 @@ strStandaloneTargetDesc = strStandalonePropViaDesc :: String strStandalonePropViaDesc = "Command to pre-process individual properties" + +-- | Additional template variable file flag description. +strStandaloneTemplateVarsArgDesc :: String +strStandaloneTemplateVarsArgDesc = + "JSON file containing additional variables to expand in template" diff --git a/ogma-core/CHANGELOG.md b/ogma-core/CHANGELOG.md index 599003b..dc61392 100644 --- a/ogma-core/CHANGELOG.md +++ b/ogma-core/CHANGELOG.md @@ -1,6 +1,6 @@ # Revision history for ogma-core -## [1.X.Y] - 2025-02-08 +## [1.X.Y] - 2025-02-09 * Import liftIO from Control.Monad.IO.Class (#215). * Remove references to old design of Ogma from hlint files (#220). @@ -17,6 +17,7 @@ * Make structured data available to ROS template (#244). * Make structured data available to FPrime template (#246). * Equalize backends (#248). +* Update ROS, FPrime, standalone backends to process template vars file (#250). ## [1.6.0] - 2025-01-21 diff --git a/ogma-core/src/Command/FPrimeApp.hs b/ogma-core/src/Command/FPrimeApp.hs index ca3ade8..14336ef 100644 --- a/ogma-core/src/Command/FPrimeApp.hs +++ b/ogma-core/src/Command/FPrimeApp.hs @@ -49,7 +49,9 @@ import qualified Control.Exception as E import Control.Monad.Except ( ExceptT(..), liftEither, runExceptT, throwError ) import Control.Monad.IO.Class ( liftIO ) -import Data.Aeson ( ToJSON, eitherDecode, object, toJSON ) +import Data.Aeson ( ToJSON, Value (Null, Object), + eitherDecode, object, toJSON ) +import Data.Aeson.KeyMap ( union ) import Data.Char ( toUpper ) import Data.List ( isInfixOf, isPrefixOf, find ) import Data.Maybe ( fromMaybe, mapMaybe ) @@ -95,9 +97,11 @@ command options = processResult $ do -- Obtain template dir templateDir <- locateTemplateDir mTemplateDir "fprime" + templateVars <- parseTemplateVarsFile templateVarsF + appData <- command' options functions - let subst = toJSON appData + let subst = mergeObjects (toJSON appData) templateVars -- Expand template ExceptT $ fmap (makeLeftE cannotCopyTemplate) $ E.try $ @@ -105,9 +109,10 @@ command options = processResult $ do where - targetDir = commandTargetDir options - mTemplateDir = commandTemplateDir options - functions = exprPair (commandPropFormat options) + targetDir = commandTargetDir options + mTemplateDir = commandTemplateDir options + functions = exprPair (commandPropFormat options) + templateVarsF = commandExtraVars options command' :: CommandOptions -> ExprPair @@ -165,6 +170,9 @@ data CommandOptions = CommandOptions , commandPropFormat :: String -- ^ Format used for input properties. , commandPropVia :: Maybe String -- ^ Use external command to -- pre-process system properties. + , commandExtraVars :: Maybe FilePath -- ^ File containing additional + -- variables to make available to the + -- template. } -- | Return the variable information needed to generate declarations @@ -318,6 +326,20 @@ parseVarDBFile (Just fn) = ExceptT $ makeLeftE (cannotOpenDB fn) <$> (E.try $ fmap read <$> lines <$> readFile fn) +-- | Process a JSON file with additional template variables to make available +-- during template expansion. +parseTemplateVarsFile :: Maybe FilePath + -> ExceptT ErrorTriplet IO Value +parseTemplateVarsFile Nothing = return $ object [] +parseTemplateVarsFile (Just fp) = do + content <- liftIO $ B.safeReadFile fp + let value = eitherDecode =<< content + case value of + Right x@(Object _) -> return x + Right x@Null -> return x + Right _ -> throwError (cannotReadObjectTemplateVars fp) + _ -> throwError (cannotOpenTemplateVars fp) + -- | Check that the arguments provided are sufficient to operate. -- -- The backend provides several modes of operation, which are selected @@ -497,6 +519,24 @@ commandIncorrectFormatSpec formatFile = "The format specification " ++ formatFile ++ " does not exist or is not " ++ "readable" +-- | Exception handler to deal with the case in which the template vars file +-- cannot be opened. +cannotOpenTemplateVars :: FilePath -> ErrorTriplet +cannotOpenTemplateVars file = + ErrorTriplet ecCannotOpenTemplateVarsFile msg (LocationFile file) + where + msg = + "Cannot open file with additional template variables: " ++ file + +-- | Exception handler to deal with the case in which the template vars file +-- cannot be opened. +cannotReadObjectTemplateVars :: FilePath -> ErrorTriplet +cannotReadObjectTemplateVars file = + ErrorTriplet ecCannotReadObjectTemplateVarsFile msg (LocationFile file) + where + msg = + "Cannot open file with additional template variables: " ++ file + -- | Exception handler to deal with the case of files that cannot be -- copied/generated due lack of space or permissions or some I/O error. cannotCopyTemplate :: ErrorTriplet @@ -534,6 +574,14 @@ ecCannotOpenHandlersFile = 1 ecIncorrectFormatFile :: ErrorCode ecIncorrectFormatFile = 1 +-- | Error: the template vars file provided by the user cannot be opened. +ecCannotOpenTemplateVarsFile :: ErrorCode +ecCannotOpenTemplateVarsFile = 1 + +-- | Error: the template variables file passed does not contain a JSON object. +ecCannotReadObjectTemplateVarsFile :: ErrorCode +ecCannotReadObjectTemplateVarsFile = 1 + -- | Error: the files cannot be copied/generated due lack of space or -- permissions or some I/O error. ecCannotCopyTemplate :: ErrorCode @@ -552,6 +600,15 @@ locateTemplateDir mTemplateDir name = dataDir <- getDataDir return $ dataDir "templates" name +-- | Merge two JSON objects. +-- +-- Fails if the values are not objects or null. +mergeObjects :: Value -> Value -> Value +mergeObjects (Object m1) (Object m2) = Object (union m1 m2) +mergeObjects obj Null = obj +mergeObjects Null obj = obj +mergeObjects _ _ = error "The values passed are not objects" + -- | Replace the left Exception in an Either. makeLeftE :: c -> Either E.SomeException b -> Either c b makeLeftE c (Left _) = Left c diff --git a/ogma-core/src/Command/ROSApp.hs b/ogma-core/src/Command/ROSApp.hs index 85daa99..ed5e7dd 100644 --- a/ogma-core/src/Command/ROSApp.hs +++ b/ogma-core/src/Command/ROSApp.hs @@ -53,7 +53,9 @@ import qualified Control.Exception as E import Control.Monad.Except (ExceptT (..), liftEither, runExceptT, throwError) import Control.Monad.IO.Class (liftIO) -import Data.Aeson (ToJSON(..), eitherDecode) +import Data.Aeson (ToJSON (..), Value (Null, Object), + eitherDecode, object) +import Data.Aeson.KeyMap (union) import Data.List (isInfixOf, isPrefixOf, find) import Data.Maybe (fromMaybe, mapMaybe) import GHC.Generics (Generic) @@ -98,9 +100,11 @@ command options = processResult $ do -- Obtain template dir templateDir <- locateTemplateDir mTemplateDir "ros" + templateVars <- parseTemplateVarsFile templateVarsF + appData <- command' options functions - let subst = toJSON appData + let subst = mergeObjects (toJSON appData) templateVars -- Expand template ExceptT $ fmap (makeLeftE cannotCopyTemplate) $ E.try $ @@ -108,9 +112,10 @@ command options = processResult $ do where - targetDir = commandTargetDir options - mTemplateDir = commandTemplateDir options - functions = exprPair (commandPropFormat options) + targetDir = commandTargetDir options + mTemplateDir = commandTemplateDir options + functions = exprPair (commandPropFormat options) + templateVarsF = commandExtraVars options command' :: CommandOptions -> ExprPair @@ -167,6 +172,9 @@ data CommandOptions = CommandOptions , commandPropFormat :: String -- ^ Format used for input properties. , commandPropVia :: Maybe String -- ^ Use external command to -- pre-process system properties. + , commandExtraVars :: Maybe FilePath -- ^ File containing additional + -- variables to make available to the + -- template. } -- | Return the variable information needed to generate declarations @@ -333,6 +341,20 @@ parseVarDBFile (Just fn) = ExceptT $ makeLeftE (cannotOpenDB fn) <$> (E.try $ fmap read <$> lines <$> readFile fn) +-- | Process a JSON file with additional template variables to make available +-- during template expansion. +parseTemplateVarsFile :: Maybe FilePath + -> ExceptT ErrorTriplet IO Value +parseTemplateVarsFile Nothing = return $ object [] +parseTemplateVarsFile (Just fp) = do + content <- liftIO $ B.safeReadFile fp + let value = eitherDecode =<< content + case value of + Right x@(Object _) -> return x + Right x@Null -> return x + Right _ -> throwError (cannotReadObjectTemplateVars fp) + _ -> throwError (cannotOpenTemplateVars fp) + -- | Check that the arguments provided are sufficient to operate. -- -- The backend provides several modes of operation, which are selected @@ -512,6 +534,24 @@ commandIncorrectFormatSpec formatFile = "The format specification " ++ formatFile ++ " does not exist or is not " ++ "readable" +-- | Exception handler to deal with the case in which the template vars file +-- cannot be opened. +cannotOpenTemplateVars :: FilePath -> ErrorTriplet +cannotOpenTemplateVars file = + ErrorTriplet ecCannotOpenTemplateVarsFile msg (LocationFile file) + where + msg = + "Cannot open file with additional template variables: " ++ file + +-- | Exception handler to deal with the case in which the template vars file +-- cannot be opened. +cannotReadObjectTemplateVars :: FilePath -> ErrorTriplet +cannotReadObjectTemplateVars file = + ErrorTriplet ecCannotReadObjectTemplateVarsFile msg (LocationFile file) + where + msg = + "Cannot open file with additional template variables: " ++ file + -- | Exception handler to deal with the case of files that cannot be -- copied/generated due lack of space or permissions or some I/O error. cannotCopyTemplate :: ErrorTriplet @@ -549,6 +589,14 @@ ecCannotOpenHandlersFile = 1 ecIncorrectFormatFile :: ErrorCode ecIncorrectFormatFile = 1 +-- | Error: the template vars file provided by the user cannot be opened. +ecCannotOpenTemplateVarsFile :: ErrorCode +ecCannotOpenTemplateVarsFile = 1 + +-- | Error: the template variables file passed does not contain a JSON object. +ecCannotReadObjectTemplateVarsFile :: ErrorCode +ecCannotReadObjectTemplateVarsFile = 1 + -- | Error: the files cannot be copied/generated due lack of space or -- permissions or some I/O error. ecCannotCopyTemplate :: ErrorCode @@ -567,6 +615,15 @@ locateTemplateDir mTemplateDir name = dataDir <- getDataDir return $ dataDir "templates" name +-- | Merge two JSON objects. +-- +-- Fails if the values are not objects or null. +mergeObjects :: Value -> Value -> Value +mergeObjects (Object m1) (Object m2) = Object (union m1 m2) +mergeObjects obj Null = obj +mergeObjects Null obj = obj +mergeObjects _ _ = error "The values passed are not objects" + -- | Replace the left Exception in an Either. makeLeftE :: c -> Either E.SomeException b -> Either c b makeLeftE c (Left _) = Left c diff --git a/ogma-core/src/Command/Standalone.hs b/ogma-core/src/Command/Standalone.hs index 3c30a2d..d2cc829 100644 --- a/ogma-core/src/Command/Standalone.hs +++ b/ogma-core/src/Command/Standalone.hs @@ -43,9 +43,11 @@ module Command.Standalone -- External imports import Control.Exception as E -import Control.Monad.Except (ExceptT (..), liftEither, runExceptT) +import Control.Monad.Except (ExceptT (..), liftEither, runExceptT, throwError) import Control.Monad.IO.Class (liftIO) -import Data.Aeson (ToJSON, decode, eitherDecode, toJSON) +import Data.Aeson (ToJSON (..), Value (Null, Object), decode, + eitherDecode, object) +import Data.Aeson.KeyMap (union) import Data.ByteString.Lazy (fromStrict) import Data.List (isInfixOf, isPrefixOf, nub, (\\)) import Data.Maybe (fromMaybe) @@ -99,9 +101,11 @@ command options = processResult $ do -- Obtain template dir templateDir <- locateTemplateDir mTemplateDir "standalone" + templateVars <- parseTemplateVarsFile templateVarsF + appData <- command' options functions - let subst = toJSON appData + let subst = mergeObjects (toJSON appData) templateVars -- Expand template ExceptT $ fmap (makeLeftE cannotCopyTemplate) $ E.try $ @@ -109,9 +113,10 @@ command options = processResult $ do where - targetDir = commandTargetDir options - mTemplateDir = commandTemplateDir options - functions = exprPair (commandPropFormat options) + targetDir = commandTargetDir options + mTemplateDir = commandTemplateDir options + functions = exprPair (commandPropFormat options) + templateVarsF = commandExtraVars options -- | Generate a new standalone Copilot monitor that implements the spec in an -- input file, using a subexpression handler. @@ -170,6 +175,9 @@ data CommandOptions = CommandOptions , commandFilename :: String , commandPropVia :: Maybe String -- ^ Use external command to -- pre-process system properties. + , commandExtraVars :: Maybe FilePath -- ^ File containing additional + -- variables to make available to the + -- template. } -- * Mapping of types from input format to Copilot @@ -258,6 +266,21 @@ parseInputFile fp opts (ExprPairT parse replace print ids def) = case res of Left _ -> return $ Left $ cannotOpenInputFile fp Right x -> return $ Right x + +-- | Process a JSON file with additional template variables to make available +-- during template expansion. +parseTemplateVarsFile :: Maybe FilePath + -> ExceptT ErrorTriplet IO Value +parseTemplateVarsFile Nothing = return $ object [] +parseTemplateVarsFile (Just fp) = do + content <- liftIO $ B.safeReadFile fp + let value = eitherDecode =<< content + case value of + Right x@(Object _) -> return x + Right x@Null -> return x + Right _ -> throwError (cannotReadObjectTemplateVars fp) + _ -> throwError (cannotOpenTemplateVars fp) + -- * Handler for boolean expressions -- | Handler for boolean expressions that knows how to parse them, replace @@ -361,6 +384,24 @@ commandIncorrectFormatSpec formatFile = "The format specification " ++ formatFile ++ " does not exist or is not " ++ "readable" +-- | Exception handler to deal with the case in which the template vars file +-- cannot be opened. +cannotOpenTemplateVars :: FilePath -> ErrorTriplet +cannotOpenTemplateVars file = + ErrorTriplet ecCannotOpenTemplateVarsFile msg (LocationFile file) + where + msg = + "Cannot open file with additional template variables: " ++ file + +-- | Exception handler to deal with the case in which the template vars file +-- cannot be opened. +cannotReadObjectTemplateVars :: FilePath -> ErrorTriplet +cannotReadObjectTemplateVars file = + ErrorTriplet ecCannotReadObjectTemplateVarsFile msg (LocationFile file) + where + msg = + "Cannot open file with additional template variables: " ++ file + -- | Exception handler to deal with the case of files that cannot be -- copied/generated due lack of space or permissions or some I/O error. cannotCopyTemplate :: ErrorTriplet @@ -394,6 +435,14 @@ ecIncorrectSpec = 1 ecIncorrectFormatFile :: ErrorCode ecIncorrectFormatFile = 1 +-- | Error: the template vars file provided by the user cannot be opened. +ecCannotOpenTemplateVarsFile :: ErrorCode +ecCannotOpenTemplateVarsFile = 1 + +-- | Error: the template variables file passed does not contain a JSON object. +ecCannotReadObjectTemplateVarsFile :: ErrorCode +ecCannotReadObjectTemplateVarsFile = 1 + -- | Error: the files cannot be copied/generated due lack of space or -- permissions or some I/O error. ecCannotCopyTemplate :: ErrorCode @@ -428,6 +477,15 @@ locateTemplateDir mTemplateDir name = dataDir <- getDataDir return $ dataDir "templates" name +-- | Merge two JSON objects. +-- +-- Fails if the values are not objects or null. +mergeObjects :: Value -> Value -> Value +mergeObjects (Object m1) (Object m2) = Object (union m1 m2) +mergeObjects obj Null = obj +mergeObjects Null obj = obj +mergeObjects _ _ = error "The values passed are not objects" + -- | Replace the left Exception in an Either. makeLeftE :: c -> Either E.SomeException b -> Either c b makeLeftE c (Left _) = Left c diff --git a/ogma-core/tests/Main.hs b/ogma-core/tests/Main.hs index 89e8091..b550e85 100644 --- a/ogma-core/tests/Main.hs +++ b/ogma-core/tests/Main.hs @@ -111,6 +111,7 @@ testStandaloneFCS file success = do , commandTargetDir = targetDir , commandTemplateDir = Nothing , commandPropVia = Nothing + , commandExtraVars = Nothing } result <- command opts @@ -147,6 +148,7 @@ testStandaloneFDB file success = do , commandTargetDir = targetDir , commandTemplateDir = Nothing , commandPropVia = Nothing + , commandExtraVars = Nothing } result <- command opts