Skip to content

Commit 758922f

Browse files
authored
Refactor files (#52)
1 parent c904264 commit 758922f

File tree

14 files changed

+291
-236
lines changed

14 files changed

+291
-236
lines changed

app/Main.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ import Data.Tuple.Extra (uncurry3)
55
import System.Environment
66
import System.IO
77

8-
import Config
8+
import Constants
9+
import LoadConfig
910
import RunCommands
11+
import TerminalUtils
12+
import Types
1013
import Watcher
1114

1215
main :: IO ()

haskellings.cabal

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,15 @@ source-repository head
2121

2222
library
2323
exposed-modules:
24-
Config
24+
Constants
2525
DirectoryUtils
2626
ExerciseList
2727
ExecutableExercises
28+
LoadConfig
29+
Processor
2830
RunCommands
29-
Utils
31+
TerminalUtils
32+
Types
3033
Watcher
3134
other-modules:
3235
Paths_haskellings
@@ -47,14 +50,16 @@ library
4750
, time
4851
, yaml
4952
default-language: Haskell2010
53+
ghc-options:
54+
-fwarn-unused-imports
5055

5156
executable haskellings
5257
main-is: Main.hs
5358
other-modules:
5459
Paths_haskellings
5560
hs-source-dirs:
5661
app
57-
ghc-options: -threaded -rtsopts -with-rtsopts=-N
62+
ghc-options: -fwarn-unused-imports -threaded -rtsopts -with-rtsopts=-N
5863
build-depends:
5964
base >=4.7 && <5
6065
, containers
@@ -67,7 +72,7 @@ test-suite haskellings-tests
6772
type: exitcode-stdio-1.0
6873
hs-source-dirs:
6974
tests
70-
ghc-options: -threaded -rtsopts -with-rtsopts=-N
75+
ghc-options: -fwarn-unused-imports -threaded -rtsopts -with-rtsopts=-N
7176
build-depends:
7277
base >=4.7 && <5
7378
, containers

src/Constants.hs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{- Constants used throughout the program,
2+
often related to configuration.
3+
-}
4+
module Constants where
5+
6+
import Data.Maybe
7+
import System.Environment
8+
9+
ghcVersion :: String
10+
ghcVersion = "ghc-8.10.4"
11+
12+
ghcVersionNumber :: String
13+
ghcVersionNumber = "8.10.4"
14+
15+
projectRootDirName :: String
16+
projectRootDirName = "haskellings"
17+
18+
configFileName :: String
19+
configFileName = "config.yaml"
20+
21+
-- On CircleCI, the root directory shows up as "project'
22+
ciEnvName :: String
23+
ciEnvName = "HASKELLINGS_CI_ENV"
24+
25+
envIsCi :: IO Bool
26+
envIsCi = isJust <$> lookupEnv ciEnvName
27+
28+
ciProjectRootDirName :: String
29+
ciProjectRootDirName = "project"
30+
31+
haskellingsVersion :: String
32+
haskellingsVersion = "0.8.0.0"
33+
34+
mainProjectExercisesDir :: String
35+
mainProjectExercisesDir = "exercises"
36+
37+
-- A listing of packages required by exercises, so we can use them
38+
-- to filter Stack snapshots
39+
haskellingsRequiredLibs :: [String]
40+
haskellingsRequiredLibs =
41+
[ "tasty"
42+
, "tasty-hunit"
43+
]

src/DirectoryUtils.hs

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,72 @@
1+
{- Utility functions for manipulating filepaths and directories.
2+
-}
13
module DirectoryUtils where
24

3-
import Control.Exception (Exception, catch)
4-
import Data.List (dropWhileEnd, isInfixOf, isSuffixOf)
5-
import Data.List.Extra (takeWhileEnd)
6-
import qualified Data.Sequence as S
5+
import Control.Concurrent
6+
import Control.Exception (catch)
7+
import Data.Char
8+
import Data.List (isSuffixOf)
9+
import Data.List.Extra (upper)
10+
import qualified Data.Map as M
11+
import qualified Data.Sequence as S
712
import System.Directory
8-
import System.FilePath (takeDirectory, takeFileName, (</>))
9-
import System.Info (os)
13+
import System.FilePath (takeBaseName, takeFileName, (</>))
14+
import System.Info (os)
15+
16+
import Types
1017

1118
isWindows :: Bool
1219
isWindows = os `notElem` ["linux", "unix", "darwin"]
1320

21+
isHaskellFile :: FilePath -> Bool
22+
isHaskellFile = isSuffixOf ".hs"
23+
24+
-- Probably a good idea to first check that it is a Haskell file first
25+
haskellModuleName :: FilePath -> FilePath
26+
haskellModuleName = takeBaseName
27+
28+
haskellFileName :: FilePath -> FilePath
29+
haskellFileName exName = exName ++ ".hs"
30+
31+
fileContainsNotDone :: FilePath -> IO Bool
32+
fileContainsNotDone fullFp = do
33+
fileLines <- lines <$> readFile fullFp
34+
return (any isDoneLine fileLines)
35+
where
36+
isDoneLine :: String -> Bool
37+
isDoneLine l = (upper . filter (not . isSpace) $ l) == "--IAMNOTDONE"
38+
39+
fullExerciseFp :: FilePath -> FilePath -> ExerciseInfo -> FilePath
40+
fullExerciseFp projectRoot exercisesExt (ExerciseInfo exName exDir _ _) =
41+
projectRoot </> exercisesExt </> exDir </> haskellFileName exName
42+
43+
withFileLock :: FilePath -> ProgramConfig -> IO a -> IO a
44+
withFileLock fp config action = case M.lookup fp (fileLocks config) of
45+
Nothing -> action
46+
Just lock -> do
47+
putMVar lock ()
48+
result <- action
49+
takeMVar lock
50+
return result
51+
52+
-- Create a directory. Run the action depending on that directory,
53+
-- and then clean the directory up.
54+
withDirectory :: FilePath -> IO a -> IO a
55+
withDirectory dirPath action = do
56+
createDirectoryIfMissing True dirPath
57+
res <- action
58+
removeDirectoryRecursive dirPath
59+
return res
60+
1461
returnIfDirExists :: FilePath -> IO (Maybe FilePath)
1562
returnIfDirExists fp = do
1663
exists <- doesDirectoryExist fp
1764
if exists
1865
then return (Just fp)
1966
else return Nothing
2067

68+
---------- Directory Search Functions ----------
69+
2170
searchForDirectoryContaining :: FilePath -> String -> IO (Maybe FilePath)
2271
searchForDirectoryContaining searchRoot directoryToFind = fpBFS predicate (S.singleton searchRoot)
2372
where

src/ExecutableExercises.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
{- Lists inputs and output predicates for
2+
executable exercises.
3+
-}
14
module ExecutableExercises where
25

36
import Data.List (isPrefixOf)

src/ExerciseList.hs

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,10 @@
1+
{- Definitive list of exercises in Haskellings -}
12
module ExerciseList where
23

34
import qualified Data.Map as M
45

56
import ExecutableExercises
6-
7-
-- There are three types of exercises.
8-
-- 1. Some succeed once they have compiled (CompileOnly).
9-
-- 2. Some require that unit tests pass on the exercise functions (UnitTests)
10-
-- 3. Others involve some degree of IO. The User can use 'haskellings exec' on
11-
-- these. There is one set of inputs and expected outputs as a quick test,
12-
-- when the exercise is run via 'haskellings run' or the Watcher.
13-
data ExerciseType =
14-
CompileOnly |
15-
UnitTests |
16-
-- One set of expected input lines and predicate for output lines.
17-
Executable [String] ([String] -> Bool)
18-
19-
-- Manual instances needed because 'Executable' contains a function.
20-
instance Eq ExerciseType where
21-
CompileOnly == CompileOnly = True
22-
UnitTests == UnitTests = True
23-
(Executable _ _) == (Executable _ _) = True
24-
_ == _ = False
25-
26-
instance Show ExerciseType where
27-
show CompileOnly = "CompileOnly"
28-
show UnitTests = "UnitTests"
29-
show (Executable _ _) = "Executable"
30-
31-
data ExerciseInfo = ExerciseInfo
32-
{ exerciseName :: String
33-
, exerciseDirectory :: String
34-
, exerciseType :: ExerciseType
35-
, exerciseHint :: String
36-
} deriving (Show, Eq)
7+
import Types
378

389
allExercises :: [ExerciseInfo]
3910
allExercises =

0 commit comments

Comments
 (0)