<commit_before>{-
HAAP: Haskell Automated Assessment Platform

This module provides basic IO functionalities.
-}

{-# LANGUAGE FlexibleContexts, DeriveGeneric, ScopedTypeVariables #-}

module HAAP.IO where

import HAAP.Core
import HAAP.Log
import HAAP.Pretty
import HAAP.Plugin

import Control.DeepSeq as DeepSeq
import Control.Monad.IO.Class
import qualified Control.Monad.Reader as Reader
import Control.Monad.Catch
import Control.Monad.Except
import Control.Monad
import Control.Exception (evaluate)

import Data.Default
import Data.Text (Text(..))
import qualified Data.Text as Text
import Data.Foldable
import Data.Typeable
import Data.Proxy
import Data.String
import Data.Bifunctor (bimap)
import Data.Binary
import qualified Data.ByteString.Lazy as BS

import System.Timeout
import System.FilePath
import System.Exit
import System.Process
import System.Directory
import System.Environment
import System.FilePath.GlobPattern


import Control.Concurrent.Async
import Control.Concurrent (threadDelay)

import Test.QuickCheck

import Text.Read

import GHC.Stack
import System.IO

import Shelly (Sh(..),catchany_sh)
import qualified Shelly as Sh

instance (MonadIO m,HaapStack t m) => MonadIO (Haap t m) where
    {-# INLINE liftIO #-}
    liftIO io = haapLiftIO $ runIOCore (def) io

data Sandbox
    = NoSandbox
    | Sandbox (Maybe FilePath) -- optional config file

mapSandboxCfg :: (FilePath -> FilePath) -> Sandbox -> Sandbox
mapSandboxCfg f NoSandbox = NoSandbox
mapSandboxCfg f (Sandbox mb) = Sandbox $ fmap f mb

data IOArgs = IOArgs
    { ioTimeout :: Maybe Int -- in seconds
    , ioSilent :: Bool -- run silently without printing to stderr or stdout
    , ioStdin :: Maybe Text -- input file or handle for processes
    , ioSandbox :: Sandbox -- run inside a cabal sandbox (with given config file) or not; relative to the current path
    , ioEscaping :: Bool -- escape shell characters or not
    , ioEnv :: [(String,FilePath)] -- additional environment variables
    , ioCmd :: Maybe String -- environment command (such as env, bash)
    , ioHidden :: Bool -- run without reporting errors 
    }

addIOCmd :: Maybe String -> IOArgs -> IOArgs
addIOCmd Nothing io = io
addIOCmd (Just cmd) io = io { ioCmd = Just cmd }

addIOEnv :: [(String,FilePath)] -> IOArgs -> IOArgs
addIOEnv xs io = io { ioEnv = ioEnv io ++ xs }

data IOResult = IOResult
    { resExitCode :: Int
    , resStdout :: Text
    , resStderr :: Text
    } deriving (Generic)
instance NFData IOResult where

resOk :: IOResult -> Bool
resOk = (==0) . resExitCode

exitCode :: ExitCode -> Int
exitCode (ExitFailure i) = i
exitCode (ExitSuccess) = 0

instance Monoid IOResult where
    mempty = IOResult 0 Text.empty Text.empty
    mappend x y = IOResult
        (resExitCode x `min` resExitCode y)
        (resStdout x `Text.append` resStdout y)
        (resStdout x `Text.append` resStdout y)

instance Out IOResult where
    docPrec i x = doc x
    doc io =   text "Output:" $+$ text (Text.unpack $ resStdout io)
           $+$ text "Errors:" $+$ text (Text.unpack $ resStderr io)<commit_msg>ghc 8.4<commit_after>{-
HAAP: Haskell Automated Assessment Platform

This module provides basic IO functionalities.
-}

{-# LANGUAGE FlexibleContexts, DeriveGeneric, ScopedTypeVariables #-}

module HAAP.IO where

import HAAP.Core
import HAAP.Log
import HAAP.Pretty
import HAAP.Plugin

import Control.DeepSeq as DeepSeq
import Control.Monad.IO.Class
import qualified Control.Monad.Reader as Reader
import Control.Monad.Catch
import Control.Monad.Except
import Control.Monad
import Control.Exception (evaluate)

import Data.Default
import Data.Semigroup
import Data.Text (Text(..))
import qualified Data.Text as Text
import Data.Foldable
import Data.Typeable
import Data.Proxy
import Data.String
import Data.Bifunctor (bimap)
import Data.Binary
import qualified Data.ByteString.Lazy as BS

import System.Timeout
import System.FilePath
import System.Exit
import System.Process
import System.Directory
import System.Environment
import System.FilePath.GlobPattern


import Control.Concurrent.Async
import Control.Concurrent (threadDelay)

import Test.QuickCheck

import Text.Read

import GHC.Stack
import System.IO

import Shelly (Sh(..),catchany_sh)
import qualified Shelly as Sh

instance (MonadIO m,HaapStack t m) => MonadIO (Haap t m) where
    {-# INLINE liftIO #-}
    liftIO io = haapLiftIO $ runIOCore (def) io

data Sandbox
    = NoSandbox
    | Sandbox (Maybe FilePath) -- optional config file

mapSandboxCfg :: (FilePath -> FilePath) -> Sandbox -> Sandbox
mapSandboxCfg f NoSandbox = NoSandbox
mapSandboxCfg f (Sandbox mb) = Sandbox $ fmap f mb

data IOArgs = IOArgs
    { ioTimeout :: Maybe Int -- in seconds
    , ioSilent :: Bool -- run silently without printing to stderr or stdout
    , ioStdin :: Maybe Text -- input file or handle for processes
    , ioSandbox :: Sandbox -- run inside a cabal sandbox (with given config file) or not; relative to the current path
    , ioEscaping :: Bool -- escape shell characters or not
    , ioEnv :: [(String,FilePath)] -- additional environment variables
    , ioCmd :: Maybe String -- environment command (such as env, bash)
    , ioHidden :: Bool -- run without reporting errors 
    }

addIOCmd :: Maybe String -> IOArgs -> IOArgs
addIOCmd Nothing io = io
addIOCmd (Just cmd) io = io { ioCmd = Just cmd }

addIOEnv :: [(String,FilePath)] -> IOArgs -> IOArgs
addIOEnv xs io = io { ioEnv = ioEnv io ++ xs }

data IOResult = IOResult
    { resExitCode :: Int
    , resStdout :: Text
    , resStderr :: Text
    } deriving (Generic)
instance NFData IOResult where

resOk :: IOResult -> Bool
resOk = (==0) . resExitCode

exitCode :: ExitCode -> Int
exitCode (ExitFailure i) = i
exitCode (ExitSuccess) = 0

instance Semigroup IOResult where
    <> = mappend

instance Monoid IOResult where
    mempty = IOResult 0 Text.empty Text.empty
    mappend x y = IOResult
        (resExitCode x `min` resExitCode y)
        (resStdout x `Text.append` resStdout y)
        (resStdout x `Text.append` resStdout y)

instance Out IOResult where
    docPrec i x = doc x
    doc io =   text "Output:" $+$ text (Text.unpack $ resStdout io)
           $+$ text "Errors:" $+$ text (Text.unpack $ resStderr io)
{'fraction_non_alphanumeric': 0.08966516419832582, 'fraction_numerical': 0.00128783000643915, 'mean_word_length': 3.6784638554216866, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2431740', 'n_tokens_mistral': 1987, 'n_tokens_neox': 1915, 'n_words': 681}