packages feed

elm-init 1.0.1.0 → 1.0.1.1

raw patch · 7 files changed

+258/−211 lines, 7 filesdep +base-unicode-symbolsdep +processdep ~basedep ~directory

Dependencies added: base-unicode-symbols, process

Dependency ranges changed: base, directory

Files

elm-init.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                elm-init-version:             1.0.1.0+version:             1.0.1.1 synopsis:            Set up basic structure for an elm project description:   Initialize a new empty elm project with some basic scaffolding according to 'https://github.com/evancz/elm-architecture-tutorial'.@@ -14,6 +14,7 @@ category:            Development build-type:          Simple cabal-version:       >=1.10+tested-with:         GHC >= 7.6  Data-dir: resources @@ -27,6 +28,7 @@   licenses/LGPL3   licenses/MIT   index.html+  .gitignore  Extra-source-files:   README.md@@ -41,16 +43,18 @@     ElmInit.Util   -- other-extensions:   build-depends:-      base >=4.8 && <5.0,+      base >=4.6 && <5.0,       filepath >= 1.4,-      directory >= 1.2,+      directory >= 1.2.3,       file-embed >= 0.0.8,       bytestring >= 0.10,       aeson >= 0.8,       aeson-pretty >= 0.7,       text >= 1.2,       containers >= 0.5,-      time+      time,+      base-unicode-symbols,+      process   hs-source-dirs:      src   default-language:    Haskell2010   ghc-options:@@ -64,4 +68,4 @@   type:     git   branch:   master   location: git://github.com/JustusAdam/elm-init.git-  tag:      1.0.1.0+  tag:      1.0.1.1
+ resources/.gitignore view
@@ -0,0 +1,2 @@+elm-stuff/+app.js
resources/Main.elm view
@@ -9,7 +9,7 @@  type Action = Reset -update : Action -> Model -> Model+update : Action → Model → Model update action model =   case action of-    Reset -> model+    Reset → model
src/ElmInit/Interact.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE UnicodeSyntax     #-}  module ElmInit.Interact   ( askChoicesWithOther@@ -6,24 +7,26 @@   ) where  -import           Control.Applicative ((<$>), (<*>))-import qualified Control.Arrow       as Arrow (first)-import           Data.Bool           (bool)-import           Data.Text           (append)-import           Data.Text           as Text (Text, intercalate, pack)-import           Data.Text.IO        as TextIO (getLine, putStrLn)-import           ElmInit.Util        (enumerate, getOr)-import           Prelude             hiding (getLine, putStrLn)+import           Control.Applicative         ((<$>), (<*>))+import           Control.Applicative.Unicode+import qualified Control.Arrow               as Arrow (first)+import           Control.Monad.Unicode+import           Data.Text                   (append)+import           Data.Text                   as Text (Text, intercalate, pack)+import           Data.Text.IO                as TextIO (getLine, putStrLn)+import           ElmInit.Util                (enumerate, getOr, bool)+import           Prelude                     hiding (getLine, putStrLn)+import           Prelude.Unicode  -askChoices :: Text -> Int -> [Text] -> IO Text+askChoices ∷ Text → Int → [Text] → IO Text askChoices =-  ((fmap <$> (!!) <*>) .) . askChoices'+  ((fmap <$> (!!) ⊛) ∘) ∘ askChoices'  -askChoices' :: Text -> Int -> [Text] -> IO Int+askChoices' ∷ Text → Int → [Text] → IO Int askChoices' message selected choices =-  putStrLn message >>+  putStrLn message ≫   ask out    where@@ -32,40 +35,40 @@       intercalate         "\n"         (normFormat 1 l1-          ++ (selectedFormat selected selectedElem : normFormat (selected + 1) l2tail))+          ⧺ (selectedFormat selected selectedElem : normFormat (selected + 1) l2tail)) -    enumF = flip append " )  " . pack . show-    enumFn = append "    " . enumF-    enumFs = append "  * " . enumF-    normFormat = (map (uncurry append . Arrow.first enumFn) .) . enumerate-    selectedFormat x y = (flip append y . enumFs) x+    enumF = flip append " )  " ∘ pack ∘ show+    enumFn = append "    " ∘ enumF+    enumFs = append "  * " ∘ enumF+    normFormat = (map (uncurry append ∘ Arrow.first enumFn) ∘) ∘ enumerate+    selectedFormat x y = (flip append y ∘ enumFs) x      ask a =-      putStrLn a >>-      getOr selected >>=+      putStrLn a ≫+      getOr selected ≫=         (bool-          (putStrLn "invalid choice, please choose again" >>+          (putStrLn "invalid choice, please choose again" ≫           ask a)           <$> return-          <*> (<= length choices))+          ⊛ (≤ length choices))  -askChoicesWithOther :: Text -> Int -> (Text -> Either Text a) -> [Text] -> IO a+askChoicesWithOther ∷ Text → Int → (Text → Either Text a) → [Text] → IO a askChoicesWithOther m s trans l =-    askChoices' m s (l ++ ["other (specify)"])-    >>= (flip bool getAlternative-          <$> either (const $ error "No parse") return . trans . (l !!)-          <*> (== length l))+    askChoices' m s (l ⧺ ["other (specify)"])+    ≫= (flip bool getAlternative+          <$> either (const $ error "No parse") return ∘ trans ∘ (l !!)+          ⊛ (≡ length l))    where     getAlternative =-      putStrLn "please enter an alternative" >>-      getLine >>=+      putStrLn "please enter an alternative" ≫+      getLine ≫=         (either-          (\message ->-            putStrLn "Invalid input:" >>-            putStrLn message >>+          (\message →+            putStrLn "Invalid input:" ≫+            putStrLn message ≫             getAlternative           )           return-          . trans)+          ∘ trans)
src/ElmInit/Types.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE UnicodeSyntax     #-}  module ElmInit.Types   ( Result@@ -6,70 +7,78 @@   , UserDecisions(..)   , ElmPackage(..)   , readVersion+  , makeVersion+  , Version   , makePackage   , verifyElmVersion   , readOneVersion   ) where  -import           Control.Applicative          ((<$>), (<*>))+import           Control.Applicative+import           Control.Applicative.Unicode import           Control.Monad                ((<=<)) import           Data.Aeson                   as Aeson (ToJSON, Value, object,                                                         toJSON, (.=)) import           Data.Text                    (Text, pack)-import           Data.Version                 (Version (Version), makeVersion,-                                               parseVersion, showVersion)+import           Data.Traversable             (sequenceA)+import           Data.Version                 (Version (Version), parseVersion,+                                               showVersion)+import           Prelude.Unicode import           Text.ParserCombinators.ReadP (readP_to_S)  - type Result = Either Text ()  -data CmdArgs = CmdArgs { workingDirectory :: FilePath }+data CmdArgs = CmdArgs { workingDirectory ∷ FilePath }  -data UserDecisions = Default { projectName  :: Text-                             , sourceFolder :: FilePath-                             , version      :: Version-                             , summary      :: Text-                             , repository   :: Text-                             , license      :: Text-                             , elmVersion   :: Text-                             , mainFileName :: String-                             , addIndex     :: Bool+data UserDecisions = Default { projectName  ∷ Text+                             , sourceFolder ∷ FilePath+                             , version      ∷ Version+                             , summary      ∷ Text+                             , repository   ∷ Text+                             , license      ∷ Text+                             , elmVersion   ∷ Text+                             , mainFileName ∷ String+                             , addIndex     ∷ Bool                              }  -data ElmPackage = ElmPackage { pkgVersion        :: Version-                             , pkgSummary        :: Text-                             , pkgRepository     :: Text-                             , pkgLicense        :: Text-                             , pkgDependencies   :: Aeson.Value-                             , pkgExposedModules :: [Text]-                             , pkgElmVersion     :: Text-                             , pkgSourceDirs     :: [Text]+data ElmPackage = ElmPackage { pkgVersion        ∷ Version+                             , pkgSummary        ∷ Text+                             , pkgRepository     ∷ Text+                             , pkgLicense        ∷ Text+                             , pkgDependencies   ∷ Aeson.Value+                             , pkgExposedModules ∷ [Text]+                             , pkgElmVersion     ∷ Text+                             , pkgSourceDirs     ∷ [Text]                              }  -readVersion :: String -> [(Version, String)]+readVersion ∷ String → [(Version, String)] readVersion = readP_to_S parseVersion  +makeVersion :: [Int] -> Version+makeVersion = flip Version []++ instance Aeson.ToJSON ElmPackage where   toJSON = object . sequenceA-    [ ("version" .=)          . showVersion . pkgVersion-    , ("summary" .=)          . pkgSummary-    , ("repository" .=)       . pkgRepository-    , ("license" .=)          . pkgLicense-    , ("dependencies" .=)     . pkgDependencies-    , ("exposed-modules" .=)  . pkgExposedModules-    , ("elm-version" .=)      . pkgElmVersion-    , ("source-directories".=). pkgSourceDirs+    [ ("version" .=)          ∘ showVersion ∘ pkgVersion+    , ("summary" .=)          ∘ pkgSummary+    , ("repository" .=)       ∘ pkgRepository+    , ("license" .=)          ∘ pkgLicense+    , ("dependencies" .=)     ∘ pkgDependencies+    , ("exposed-modules" .=)  ∘ pkgExposedModules+    , ("elm-version" .=)      ∘ pkgElmVersion+    , ("source-directories".=)∘ pkgSourceDirs     ]  -emptyDecisions :: UserDecisions+emptyDecisions ∷ UserDecisions emptyDecisions =   Default { summary       = ""           , repository    = ""@@ -83,27 +92,27 @@           }  -makePackage :: UserDecisions -> ElmPackage+makePackage ∷ UserDecisions → ElmPackage makePackage = ElmPackage   <$> version-  <*> summary-  <*> repository-  <*> license-  <*> const (object [("elm-lang/core", "2.0.0 <= v < 3.0.0")])-  <*> const []-  <*> elmVersion-  <*> (:[]) . pack . sourceFolder+  ⊛ summary+  ⊛ repository+  ⊛ license+  ⊛ const (object [("elm-lang/core", "2.0.0 <= v < 3.0.0")])+  ⊛ const []+  ⊛ elmVersion+  ⊛ (:[]) . pack . sourceFolder  -readOneVersion :: String -> Either Text Version-readOneVersion = verif . readVersion+readOneVersion ∷ String → Either Text Version+readOneVersion = verif ∘ readVersion   where     verif ((v, []):_) = return v     verif []          = Left "Version must have this structure: 1.2.3"     verif (_:xs)      = verif xs  -verifyElmVersion :: String -> Either Text Version+verifyElmVersion ∷ String → Either Text Version verifyElmVersion = hasElmStructure <=< readOneVersion   where     hasElmStructure v@(Version [ _, _, _ ] []) = Right v
src/ElmInit/Util.hs view
@@ -1,33 +1,40 @@+{-# LANGUAGE UnicodeSyntax #-} module ElmInit.Util   ( exists   , getOr   , enumerate+  , bool   ) where  -import           Control.Applicative ((<$>), (<*>))-import           Control.Exception   (IOException, catch)-import           Data.Bool           (bool)-import           Data.Maybe          (fromMaybe)-import           System.Directory    (doesDirectoryExist, doesFileExist)+import           Control.Applicative         ((<$>))+import           Control.Applicative.Unicode+import           Control.Exception           (IOException, catch)+import           Prelude.Unicode+import           System.Directory            (doesDirectoryExist, doesFileExist)  -exists :: FilePath -> IO Bool+bool :: a -> a -> Bool -> a+bool a _ False = a+bool _ a True = a+++exists ∷ FilePath → IO Bool exists =   (>>=)   <$> doesFileExist-  <*> (flip bool+  ⊛ (flip bool         (return True)-        . doesDirectoryExist)+        ∘ doesDirectoryExist)  -getOr :: Read a => a -> IO a+getOr ∷ Read a ⇒ a → IO a getOr =-  catch readLn . handler+  catch readLn ∘ handler   where-    handler :: a -> IOException -> IO a-    handler = const . return+    handler ∷ a → IOException → IO a+    handler = const ∘ return  -enumerate :: Int -> [a] -> [(Int,a)]+enumerate ∷ Int → [a] → [(Int,a)] enumerate from l = zip [from..(length l)] l
src/Main.hs view
@@ -1,58 +1,68 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell   #-}+{-# LANGUAGE UnicodeSyntax     #-}  module Main (main) where  -import           Control.Applicative      ((<$>), (<*>))-import           Control.Arrow            as Arrow (first)-import           Control.Monad            (join)-import           Data.Aeson.Encode.Pretty (encodePretty)-import           Data.Bool                (bool)-import qualified Data.ByteString          as ByteString (ByteString, hPut)-import qualified Data.ByteString.Char8    as CBS (pack, unpack)-import qualified Data.ByteString.Lazy     as LBS (hPut)-import           Data.Char                (isUpper)-import           Data.FileEmbed           (embedFile)-import           Data.Text                as Text (Text, append, pack, unpack)-import qualified Data.Text.IO             as TextIO (getLine, putStrLn)+import           Control.Applicative         ((<$>), (<*>))+import           Control.Applicative.Unicode+import           Control.Arrow               as Arrow (first)+import           Control.Monad               (join, void, when)+import           Control.Monad.Unicode+import           Data.Aeson.Encode.Pretty    (encodePretty)+import qualified Data.ByteString             as ByteString (ByteString, hPut,+                                                            writeFile)+import qualified Data.ByteString.Char8       as CBS (pack, unpack)+import qualified Data.ByteString.Lazy        as LBS (hPut)+import           Data.Char                   (isUpper)+import           Data.FileEmbed              (embedFile)+import           Data.Monoid.Unicode+import           Data.Text                   as Text (Text, pack, unpack)+import qualified Data.Text.IO                as TextIO (getLine, putStrLn) import           Data.Time-import           Data.Version             (Version (..), makeVersion,-                                           showVersion)-import           ElmInit                  (CmdArgs (..), Result,-                                           UserDecisions (..), askChoices,-                                           askChoicesWithOther, exists,-                                           makePackage, verifyElmVersion)-import           Prelude                  hiding (putStrLn)-import           System.Directory         (createDirectoryIfMissing,-                                           doesDirectoryExist, doesFileExist,-                                           getCurrentDirectory, makeAbsolute)-import           System.Environment       (getArgs)-import           System.FilePath          (isValid, takeBaseName, takeExtension,-                                           (</>))-import           System.IO                (IOMode (WriteMode), withFile)-import           Text.Printf              (printf)+import           ElmInit.Types               (makeVersion, Version)+import           ElmInit                     (CmdArgs (..), Result,+                                              UserDecisions (..), askChoices,+                                              askChoicesWithOther, exists,+                                              makePackage, verifyElmVersion)+import           ElmInit.Util                (bool)+import           Prelude                     hiding (putStrLn)+import           Prelude.Unicode+import           System.Directory            (createDirectoryIfMissing,+                                              doesDirectoryExist, doesFileExist,+                                              getCurrentDirectory, makeAbsolute,+                                              withCurrentDirectory)+import           System.Environment          (getArgs)+import           System.FilePath             (isValid, takeBaseName,+                                              takeExtension, (</>))+import           System.IO                   (IOMode (WriteMode), withFile)+import           System.Process              (callProcess)+import           Text.Printf                 (printf)  -standardDirectories :: [FilePath]+standardDirectories ∷ [FilePath] standardDirectories = [ "elm-stuff" ] -standardSourceFolders :: [FilePath]+standardSourceFolders ∷ [FilePath] standardSourceFolders = [ "src" ] -standardFiles :: [(FilePath, Maybe ByteString.ByteString)]+standardFiles ∷ [(FilePath, Maybe ByteString.ByteString)] standardFiles = [ ("README.md", Nothing) ] -standardSourceFiles :: [(FilePath, Maybe ByteString.ByteString)]+standardSourceFiles ∷ [(FilePath, Maybe ByteString.ByteString)] standardSourceFiles = [] -mainFile :: String -> ByteString.ByteString-mainFile = CBS.pack . printf (CBS.unpack $(embedFile "resources/Main.elm"))+mainFile ∷ String → ByteString.ByteString+mainFile = CBS.pack ∘ printf (CBS.unpack $(embedFile "resources/Main.elm")) -indexHtml :: String -> ByteString.ByteString-indexHtml = CBS.pack . printf (CBS.unpack $(embedFile "resources/index.html"))+indexHtml ∷ String → ByteString.ByteString+indexHtml = CBS.pack ∘ printf (CBS.unpack $(embedFile "resources/index.html")) -standardLicenses :: [(Text, Maybe ByteString.ByteString)]+gitignore ∷ ByteString.ByteString+gitignore = $(embedFile "resources/.gitignore")++standardLicenses ∷ [(Text, Maybe ByteString.ByteString)] standardLicenses =   [ ("None"   , Nothing                                       )   , ("BSD3"   , Just $(embedFile "resources/licenses/BSD3"   ))@@ -64,177 +74,189 @@   , ("GPLv3"  , Just $(embedFile "resources/licenses/GPLv3"  ))   ] -defaultProjectVersion :: Version+defaultProjectVersion ∷ Version defaultProjectVersion = makeVersion [1, 0, 0] -defaultElmVersion :: Text+defaultElmVersion ∷ Text defaultElmVersion = "0.15.0 <= v < 0.16.0" -availableLicenses :: [Text]+availableLicenses ∷ [Text] availableLicenses = fst $ unzip standardLicenses -elmConfigName :: FilePath+elmConfigName ∷ FilePath elmConfigName = "elm-package.json"  -getCmdArgs :: IO CmdArgs-getCmdArgs =-  fmap CmdArgs-    (getArgs >>=-      (\args ->-        case args of-          []  -> getCurrentDirectory-          [x] -> makeAbsolute x-          _   -> error "Too many arguments"))  -- I'm so sorry+getCmdArgs ∷ IO CmdArgs+getCmdArgs = CmdArgs <$> (getArgs ≫= handleDir)+  where+    handleDir []  = getCurrentDirectory+    handleDir [x] = makeAbsolute x+    handleDir _   = error "Too many arguments"  -- I'm so sorry  -verifyWD :: FilePath -> IO FilePath+verifyWD ∷ FilePath → IO FilePath verifyWD wd =-  doesFileExist wd >>=+  doesFileExist wd ≫=     bool-      (doesDirectoryExist wd >>=+      (doesDirectoryExist wd ≫=         bool-          (TextIO.putStrLn "the chosen directory does not exist yet, shall I create it? [y/N]"-          >> getResp >>=+          (TextIO.putStrLn "the chosen directory does not exist yet, shall I create it? [y/N]" >>+          getResp ≫=             bool               (error "Project directory does not exist")  -- I'm so sorry-              makeDirs-          >> return wd)-          (return wd))+              makeDirs ≫+          return wd)+        (return wd))       (error "The chosen directory is a file, you'll have to choose a different name") -- I'm so sorry    where-    getResp :: IO Bool-    getResp = flip elem ["y", "yes"] <$> TextIO.getLine+    getResp ∷ IO Bool+    getResp = (∈ ["y", "yes"]) <$> TextIO.getLine      makeDirs = createDirectoryIfMissing True wd  -getUserDecisions :: FilePath -> IO UserDecisions+getUserDecisions ∷ FilePath → IO UserDecisions getUserDecisions wd = Default   <$> askChoicesWithOther         "project name?"         0         return         [pack $ takeBaseName wd]-  <*> askChoicesWithOther+  ⊛ askChoicesWithOther         "choose a source folder name"         0-        ((bool (Left "The filepath must be valid") <$> return <*> isValid) . unpack)  -- filepath path verifier+        ((bool (Left "The filepath must be valid") <$> return ⊛ isValid) ∘ unpack)  -- filepath path verifier         (map pack standardSourceFolders)-  <*> askChoicesWithOther+  ⊛ askChoicesWithOther         "initial project version?"         0-        (verifyElmVersion . unpack)-        [pack $ showVersion defaultProjectVersion]-  <*> (TextIO.putStrLn "a quick summary" >> TextIO.getLine)-  <*> (TextIO.putStrLn "project repository url" >> TextIO.getLine)-  <*> askChoicesWithOther+        (verifyElmVersion ∘ unpack)+        [pack $ show defaultProjectVersion]+  ⊛ (TextIO.putStrLn "a quick summary" ≫ TextIO.getLine)+  ⊛ (TextIO.putStrLn "project repository url" ≫ TextIO.getLine)+  ⊛ askChoicesWithOther         "choose a license"         0         return         availableLicenses-  <*> askChoicesWithOther+  ⊛ askChoicesWithOther         "select the elm-version"         0         return         [defaultElmVersion]-  <*> askChoicesWithOther+  ⊛ askChoicesWithOther         "What sould be the Main file?"         0         (isValidMainFile . unpack)         ["Main.elm"]-  <*> ((== "Yes") <$> askChoices+  ⊛ ((≡ "Yes") <$> askChoices         "Should I create an index.html file?"         0         ["Yes", "No"]       )  -isValidMainFile :: String -> Either Text String+isValidMainFile ∷ String → Either Text String isValidMainFile file   | null file = Left "Filename cannot be 𝜖"-  | not $ isUpper (head file) = Left "Module names (and their files) have to start with uppercase"-  | ".elm" /= takeExtension file = Left "Elm modules (such as this main file) have to end with the fileending \".elm\""+  | not $ isUpper (head file) =+    Left "Module names (and their files) have to start with uppercase"+  | ".elm" ≢ takeExtension file =+    Left "Elm modules (such as this main file) have to end with the fileending \".elm\""   | otherwise = return file  -mkFiles :: [(FilePath, Maybe ByteString.ByteString)] -> IO [Result]+mkFiles ∷ [(FilePath, Maybe ByteString.ByteString)] → IO [Result] mkFiles = mapM (uncurry mkFile)  -mkFile :: FilePath -> Maybe ByteString.ByteString -> IO Result-mkFile name defaultFile = exists name >>=+mkFile ∷ FilePath → Maybe ByteString.ByteString → IO Result+mkFile name defaultFile = exists name ≫=   bool     (withFile       name       WriteMode-      (flip (maybe (return ())) defaultFile . ByteString.hPut)-    >> return (Right ()))-    (return $ Left $ "file " `append` pack name `append` " already exists")+      (flip (maybe (return ())) defaultFile ∘ ByteString.hPut) ≫+    return (Right ()))+    (return $ Left $ "file " ⊕ pack name ⊕ " already exists")  -mkSourceFiles :: FilePath -> UserDecisions -> IO [Result]-mkSourceFiles wd (Default { mainFileName = mfn, sourceFolder = sourceF, addIndex = makeIndex }) = do+mkSourceFiles ∷ UserDecisions → IO [Result]+mkSourceFiles (Default { mainFileName = mfn, sourceFolder = sourceF, addIndex = makeIndex }) = do   let mainModule = takeBaseName mfn-  mainFileRes <- mkFile (wd  </> sourceF </> mfn) $ Just $ mainFile mainModule-  indexFileRes <- if makeIndex-    then mkFile (wd </> "index.html") $ Just $ indexHtml mainModule+  mainFileRes ← mkFile (sourceF </> mfn) $ Just $ mainFile mainModule+  indexFileRes ← if makeIndex+    then mkFile "index.html" $ Just $ indexHtml mainModule     else return $ return ()-  others <- mkFiles $ flip map standardSourceFiles $ Arrow.first ((wd </> sourceF) </>)+  others ← mkFiles standardSourceFiles   return $ mainFileRes:indexFileRes:others  -mkDirs :: FilePath -> [FilePath] -> IO ()-mkDirs = mapM_ . (createDirectoryIfMissing True .) . (</>)+mkDirs ∷ [FilePath] → IO ()+mkDirs = mapM_ (createDirectoryIfMissing True)  -writeConf :: FilePath -> UserDecisions -> IO ()-writeConf wd =+writeConf ∷ UserDecisions → IO ()+writeConf =   withFile-    (wd </> elmConfigName)+    elmConfigName     WriteMode-    . flip LBS.hPut . encodePretty . makePackage+    ∘ flip LBS.hPut ∘ encodePretty ∘ makePackage  -putLicense :: FilePath -> Text -> IO ()-putLicense wd name =+putLicense ∷ Text → IO ()+putLicense name =   case join $ lookup name standardLicenses of-    Nothing -> return ()-    Just contents -> do+    Nothing → return ()+    Just contents → do       TextIO.putStrLn "The project owner(s): (for the license)"-      authors <- getLine-      (year, _, _) <- toGregorian . utctDay <$> getCurrentTime-      writeFile (wd </> "LICENSE") $+      authors ← getLine+      (year, _, _) ← toGregorian ∘ utctDay <$> getCurrentTime+      writeFile "LICENSE" $         printf (CBS.unpack contents) year $           if null authors             then "[project owners]"             else authors  -main :: IO ()+initGit ∷ IO ()+initGit = do+  TextIO.putStrLn "Shall I initialize a git repository? [Y/n]"+  answ ← getLine+  when (answ `elem` ["y", "Y", ""]) $ do+    ByteString.writeFile ".gitignore" gitignore+    void $ callProcess "git" ["init"]+++main ∷ IO () main = do    -- get either the working directory or the directory the user entered-  wd        <- getCmdArgs >>= (verifyWD . workingDirectory)+  wd        ← getCmdArgs ≫= (verifyWD ∘ workingDirectory) -  -- ask all important input first-  decisions <- getUserDecisions wd+  withCurrentDirectory wd $ do -  -- create necessary directories-  mkDirs wd (sourceFolder decisions : standardDirectories)+    -- ask all important input first+    decisions ← getUserDecisions wd -  -- create non-dynamic files, collect errors-  resStatic <- mkFiles $ map (Arrow.first (wd </>)) standardFiles+    -- create necessary directories+    mkDirs (sourceFolder decisions : standardDirectories) -  -- create Elm source files, collect errors-  resSource <- mkSourceFiles wd decisions+    -- create non-dynamic files, collect errors+    resStatic ← mkFiles standardFiles -  -- write the package config based on the user decisions-  writeConf wd decisions+    -- create Elm source files, collect errors+    resSource ← mkSourceFiles decisions -  -- write the choosen license-  _         <- putLicense wd (license decisions)+    -- write the package config based on the user decisions+    writeConf decisions -  -- report all errors-  mapM_ (either TextIO.putStrLn return) (resStatic ++ resSource)+    -- write the choosen license+    _         ← putLicense (license decisions)++    initGit++    -- report all errors+    mapM_ (either TextIO.putStrLn return) (resStatic ⧺ resSource)