-
-
Notifications
You must be signed in to change notification settings - Fork 73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#48] Add configurations, read from the file #59
Conversation
@@ -1,6 +1,7 @@ | |||
module Summoner | |||
( module Summoner.Ansi | |||
, module Summoner.CLI | |||
, module Summoner.Config | |||
, module Summoner.Default |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am I right that Default
module will be removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it should be
src/Summoner/CLI.hs
Outdated
-- Generate the project. | ||
generateProject projectName targets | ||
runWithOptions (InitOpts projectName cliConfig maybeFile) = do | ||
file <- case maybeFile of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We really need universum
for such things (so we can use whenNothing
here) 😏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm agree with adding it after so many stupid imports..
src/Summoner/CLI.hs
Outdated
generateProject projectName targets | ||
runWithOptions (InitOpts projectName cliConfig maybeFile) = do | ||
file <- case maybeFile of | ||
Nothing -> getHomeDirectory >>= pure . (++ "/summoner.toml") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's better to use (</>)
operator instead of (++)
to make it work on Windows as well.
Also, m >>= pure . f
is f <$> m
.
src/Summoner/CLI.hs
Outdated
Right conf -> pure $ defaultConfig <> conf | ||
else pure defaultConfig | ||
-- get the final config | ||
let globalConfig = case finalise (config <> cliConfig) of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally, to me it looks slightly more cleaner when you write all configs in one place, like this:
let unionConfig = defaultConfig <> fileConfig <> cliConfig
finalConfig <- ...
src/Summoner/CLI.hs
Outdated
putStrLn "Using default config.." | ||
pure defaultConfig | ||
Right conf -> pure $ defaultConfig <> conf | ||
else pure defaultConfig |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to make unionConfig
you can just return pure mempty
here.
src/Summoner/Config.hs
Outdated
fromDecision d = snd $ head $ filter ((== d) . fst) decisionMaybe | ||
|
||
toDecision :: Maybe Bool -> Decision | ||
toDecision m = fst $ head $ filter ((== m) . snd) decisionMaybe |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lookup +
swap
here as well 👍
src/Summoner/Config.hs
Outdated
<*> pure cBench | ||
<*> fin "ghcVersions" cGhcVer | ||
where | ||
fin name = maybe (Left $ "Missing field: " <> name) Right . getLast |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, this is an interesting piece of code. Applicative
instance for Either
works in that way that it fails on first error and returns only single error to user. But it would be much more convenient to tell all absent fields at once. This actually already exist in Haskell world. There's data type called Validation
. It's like Either
(just different constructor names). But it has slightly more interesting applicative instance
. It accumulates all errors. So we can copy-paste Validation
to us and this instance and just use it here instead of Either
to output multiple errors to user regarding absent fields!
src/Summoner/Config.hs
Outdated
|
||
-- | Read configuration from the given file and return it in data type. | ||
loadFileConfig :: MonadIO m => FilePath -> m (Either Toml.EncodeException PartialConfig) | ||
loadFileConfig filePath = liftIO $ TIO.readFile filePath >>= pure . Toml.encode configT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can just use throwIO
here instead of returning Either
. If there's error in configuration we don't want to skip this file, we want to throw exception. This also will simplify code a bit in main
.
@@ -198,3 +133,23 @@ generateProject projectName Targets{..} = do | |||
"git" ["add", "."] | |||
"git" ["commit", "-m", "Create the project"] | |||
"git" ["push", "-u", "origin", "master"] | |||
|
|||
categoryText :: Text |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool idea to move this under where
.
You get the joke?) under where
is like underwear 😂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤣
src/Summoner/ProjectData.hs
Outdated
@@ -1,12 +1,22 @@ | |||
{-# LANGUAGE DeriveAnyClass #-} | |||
{-# LANGUAGE DeriveGeneric #-} | |||
{-# LANGUAGE InstanceSigs #-} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think DeriveGeneric
and InstanceSigs
should be put into default extensions safely.
data LoadTomlException = LoadTomlException FilePath String | ||
|
||
instance Show LoadTomlException where | ||
show (LoadTomlException filePath msg) = "Couldnt parse file " ++ filePath ++ ": " ++ show msg |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, sorry for that... I will add Exception
instance to EncodeException
. But I think I can't write this code better. Because for now EncodeException
contains file name only in case of parse error, not encoding error.
README.md
Outdated
`false` if you don't. If not specified it would be asked during each run of the `summoner`. | ||
* `lib` – `true` if you want to create `src` folder by default, | ||
`false` if you don't. If not specified it would be asked during each run of the `summoner`. | ||
* `exe` – `true` if you want to create `app` folder by default, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's good to add here that app
folder will contain dummy Main.hs
file and executable
target will be added to .cabal
file. Same for test
flag.
src/Summoner/CLI.hs
Outdated
generateProject projectName targets | ||
runWithOptions (InitOpts projectName cliConfig maybeFile) = do | ||
file <- case maybeFile of | ||
Nothing -> (</> "summoner.toml") <$> getHomeDirectory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can put "summoner.toml"
into Default
module. As well as IO
function which returns full path to this file.
src/Summoner/CLI.hs
Outdated
fileConfig <- | ||
if isFile | ||
then loadFileConfig file | ||
else pure mempty |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After thinking a little bit more on this, I came to decision that logic here should be slightly complicated to increase UX.
- If file exist, print information message (probably we can use
Blue
for information?) that this file configuration will be used. - If this is a default file
~/summoner.toml
and it doesn't exist then print info message that no configuration file was specified (or will be used). - If this is not a default configuration file (i.e. specified by
--file
) then we should abort immediately because I think that if you specify file manually through CLI you expect this file to exist. But if you have typo in file name, it's better to see error that such file doesn't exist and fix CLI command instead of silently continue to work.
src/Summoner/CLI.hs
Outdated
then do | ||
infoMessage $ "Configurations from " <> T.pack file <> " will be used." | ||
loadFileConfig file | ||
else if isDefault |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra space here..
src/Summoner/CLI.hs
Outdated
Success c -> c | ||
finalConfig <- case finalise unionConfig of | ||
Failure msgs -> do | ||
for_ msgs $ \msg -> errorMessage msg |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can eta-reduce lambda here
src/Summoner/CLI.hs
Outdated
loadFileConfig file | ||
else if isDefault | ||
then do | ||
warningMessage "Default config file is missing." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can add path defaultTomlFile
path to this message just in case. So stupid people won't complain in a way like It says to me that default config file is missing but I don't know where default config file should be.
src/Summoner/Question.hs
Outdated
queryManyRepeatOnFail parser question = do | ||
T.putStrLn question | ||
queryManyRepeatOnFail :: forall a . (Text -> Maybe a) -> IO [a] | ||
queryManyRepeatOnFail parser = do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need do
here and you can put promptLoop
on the same line as queryManyRepeatOnFail
Things to do
[GhcVer]
from the custom configurationsREADME
explaining how configs should work