packages feed

azubi-0.2.0.3: src/Azubi/Syntax.hs

{-|

Module      : Azubi.Syntax
Description : Basic Azubi syntax to combine 'State's
Copyright   : (c) Ingolf Wagner, 2017
License     : GPL-3
Maintainer  : azubi@ingolf-wagner.de
Stability   : experimental
Portability : POSIX

Functions to create a readable and typesafe
language, to describe system states.

-}
module Azubi.Syntax where

import           Azubi.Core.Model
import           System.FilePath.Posix

-- todo : Syntax belongs to core
{-|

Create a state that ensures that a file in @Path@ will
have the content of the String List.

Every String in the List will be a Line in the File.

-}
content :: String -> [String] -> State
content path contentToSet =
  States
    [HasFileContent path contentToSet]
    [ folderExists (takeDirectory path)
    , State [Not $ FolderExists path] [Remove path] Nothing
    , State [SkipChecks] [FileContent path contentToSet] Nothing
    ]
    (Just $ unwords ["Content for File", path])

{-|

Creates a state out of two states.
When the first State fails the second
State will not be checked nor enforced.

This can also be achieved using 'submodule':

@
stateA `requires` stateB == 'submodule' [stateB, stateA]
@

-}
requires :: State -> State -> State
stateA `requires` stateB = States [SkipChecks] [stateB, stateA] Nothing

{-|

Create a state containing of sub-states,
which have to be fulfilled in order.

If one state is not fulfilled, the following
will be ignored.

-}
submodule :: [State] -> State
submodule dependingStates = States [SkipChecks] dependingStates Nothing

{-|

make sure a folder exists

-}
folderExists :: Path -> State
folderExists path =
  let folders = reverse $ allFolders $ reverse $ splitDirectories path
  in States
       [FolderExists path]
       (map
          (\folder ->
             States
               [FolderExists folder]
               [ State
                   [Not $ DoesExist folder]
                   [Remove folder]
                   (Just $ "delete folder : " ++ folder)
               , State
                   [SkipChecks]
                   [CreateFolder folder]
                   (Just $ "create " ++ folder)
               ]
               Nothing)
          folders)
       Nothing
  where
    allFolders []     = []
    allFolders ["/"]  = []
    allFolders ["~"]  = []
    allFolders (x:xs) = joinPath (reverse $ x : xs) : allFolders xs

{-|

ensure there is a link file -> target

example:

@
link "~\/file" "~\/target"
@

will create a link at @~\/file\/@ pointing to @~\/target\/@

-}
link :: String -> String -> State
link path target =
  States
    [SymlinkExists path target]
    [ State [Not $ DoesExist path] [Remove path] Nothing
    , State [SkipChecks] [CreateSymlink path target] Nothing
    ]
    (Just $ "link " ++ path ++ " -> " ++ target)

{-|

'State' combinator.

@
[]
& folderExists "\/tmp\/foo"
& folderExists "\/tmp\/bar"
@

-}
(&) :: [State] -> State -> [State]
previouseStates & state = previouseStates ++ [state]
-- (!) :: [State] -> State -> [State]
-- states ! state = states ++ [(revertState state)]