packages feed

azubi-0.2.0.3: src/Azubi/Core/Model.hs

{-|

Module      : Azubi.Core.Model
Description : Core low level Model of Azubi
Copyright   : (c) Ingolf Wagner, 2017
License     : GPL-3
Maintainer  : azubi@ingolf-wagner.de
Stability   : experimental
Portability : POSIX

This is the lowest level of Azubi.
It should deliver only the bare
minimum to create 'State' evaluation
and 'State' enforcement.

The 'State' object is the element
a user should use to formulate more complex
situations.

The idea here is to create a simple AST which
can be run on different setups.

* export to Script
* run on the Machine (Linux, OSX and (maybe) Windows)
* run over SSH on another computer

-}
module Azubi.Core.Model where

type Path = String

type Target = String

type Argument = String

type Comment = String

{-|

A command is something that will be run.
In a normal case you put a 'Check' before
using a 'State'

When a Command get executed,
it will create a 'CommandResult'.

@ command -> exit code -> 'CommandResult' @

-}
data Command
  = Run { command          :: String
        , commandArguments :: [String]
        , commandComment   :: Maybe String }
  | FileContent { filePath    :: String
                , fileContent :: [String] }
  | CreateSymlink { linkPath   :: String
                  , linkTarget :: String }
  | CreateFolder { folderPath :: String }
  | Remove { removePath :: String }
  deriving (Show, Eq)

{-|

The Result of a 'Command' will be matched
to a 'CommandResult'. The basic rule is

@
0 -> 'Success'
_ -> 'Failure'
@

-}
data CommandResult
  = Success
  | Failure
  deriving (Show, Enum, Eq)

{-|

Gather information about a situation.

@
check -> success/failure
check -> exit code -> success/failure
@

-}
data Check
  {-|

Check if command returns exit status

@
0 -> Yes
_ -> No
@

-}
  = Check { checkCommand   :: String
          , checkArguments :: [String]
          , checkComment   :: Maybe String }
  -- | Will return `No` to "skip" the Checks.
  | SkipChecks
  -- | Opposite result of a 'Check'
  | Not Check
  -- | Check if 'Path' has content
  | HasFileContent { pathToCheck    :: String
                   , contentToCheck :: [String] }
  -- | Check if a Symbolic link exists to a specific target
  | SymlinkExists { pathToCheck   :: String
                  , targetToCheck :: String }
  -- | Check if a folder exists
  | FolderExists { pathToCheck :: String }
  -- | Check if something exists at path
  | DoesExist { pathToCheck :: String }
  deriving (Show, Eq)

{-|

The result of a 'Check'.

-}
data CheckResult
  = Yes
  | No
  deriving (Show, Enum, Eq)

{-|

The low level element to formulate a state on a machine.
If the check returns 'No' the 'Command's will run.
So the author should make sure the 'Command' will result
in a 'Yes' the next time this state will run.

All 'Check's have to return 'Yes' to avoid the 'Command's
to be run.

If a 'Command' returns a 'Failure' the following commands
will not be called.
Same holdes for 'States' if one of the states fail,
the following 'State's will not be /run/.

-}
data State
  -- | State contains checks and commands
  -- if one command failed
  -- the following commands will not be
  -- executed.
  = State { stateChecks   :: [Check]
          , stateCommands :: [Command]
          , stateComment  :: Maybe String }
  -- | To create depended states
  -- which should stop being executed
  -- when a previous state fails
  | States { stateChecks  :: [Check]
           , subStates    :: [State]
           , stateComment :: Maybe String }
  deriving (Show, Eq)

{-|

When a 'State' is /run/ it returns one of the 'StateResult's.

* positive 'CheckResult's will result in 'Fulfilled'.
* negative 'CheckResult's with positive 'CommandResult's will result in 'Fulfilled'.
* negative 'CheckResult's with negative 'CommandResult's will result in 'Unfulfilled'.

-}
data StateResult
  = Fulfilled
  | Unfulfilled
  deriving (Show, Eq, Enum)