packages feed

elm-make-0.1: src/Main.hs

{-# LANGUAGE FlexibleContexts #-}
module Main where

import Control.Monad (forM)
import Control.Monad.Error (MonadError, runErrorT, MonadIO, liftIO)
import Control.Monad.Reader (MonadReader, runReaderT, ask)
import qualified Data.List as List
import qualified Data.Map as Map
import System.Directory (doesFileExist)
import System.FilePath ((</>))
import System.Exit (exitFailure)
import System.IO (hPutStrLn, stderr)
import GHC.Conc (getNumProcessors, setNumCapabilities)

import qualified Build
import qualified CrawlPackage
import qualified CrawlProject
import qualified LoadInterfaces
import qualified Arguments
import qualified Elm.Package.Description as Desc
import qualified Elm.Package.Initialize as Initialize
import qualified Elm.Package.Paths as Path
import qualified Elm.Package.Solution as Solution
import qualified Generate
import TheMasterPlan
    ( ModuleID(ModuleID), Location, PackageID
    , ProjectSummary(..), ProjectData(..)
    )


main :: IO ()
main =
  do  args <- Arguments.parse

      result <- runErrorT (runReaderT (run args) artifactDirectory)
      case result of
        Right () ->
          return ()

        Left msg ->
          do  hPutStrLn stderr msg
              exitFailure


artifactDirectory :: FilePath
artifactDirectory =
    Path.stuffDirectory </> "build-artifacts"


run :: (MonadIO m, MonadError String m, MonadReader FilePath m)
    => Arguments.Arguments
    -> m ()
run args =
  do  numProcessors <- liftIO getNumProcessors
      liftIO (setNumCapabilities numProcessors)

      (thisPackage, publicModules, projectSummary) <-
          crawl (Arguments.autoYes args) (Arguments.files args)

      let dependencies = Map.map projectDependencies (projectData projectSummary)
      buildSummary <- LoadInterfaces.prepForBuild projectSummary

      cachePath <- ask
      liftIO $
        Build.build
            numProcessors
            thisPackage
            cachePath
            publicModules
            dependencies
            buildSummary

      Generate.generate
          cachePath
          dependencies
          (projectNatives projectSummary)
          publicModules
          (maybe "elm.js" id (Arguments.outputFile args))


crawl
    :: (MonadIO m, MonadError String m)
    => Bool
    -> [FilePath]
    -> m (PackageID, [ModuleID], ProjectSummary Location)
crawl autoYes filePaths =
  do  solution <- getSolution autoYes

      summaries <-
          forM (Map.toList solution) $ \(name,version) -> do
              let root = Path.package name version
              desc <- Desc.read (root </> Path.description)
              packageSummary <- CrawlPackage.dfsFromExposedModules root solution desc
              return (CrawlProject.canonicalizePackageSummary (name,version) packageSummary)


      desc <- Desc.read Path.description
      
      (moduleNames, packageSummary) <-
          case filePaths of
            [] ->
              do  summary <- CrawlPackage.dfsFromExposedModules "." solution desc
                  return ([], summary)

            _ -> CrawlPackage.dfsFromFiles "." solution desc filePaths

      let thisPackage =
            (Desc.name desc, Desc.version desc)

      let summary =
            CrawlProject.canonicalizePackageSummary thisPackage packageSummary

      return
          ( thisPackage
          , map (\n -> ModuleID n thisPackage) moduleNames
          , List.foldl1 CrawlProject.union (summary : summaries)
          )


getSolution :: (MonadIO m, MonadError String m) => Bool -> m Solution.Solution
getSolution autoYes =
  do  exists <- liftIO (doesFileExist Path.solvedDependencies)
      if exists
          then Solution.read Path.solvedDependencies
          else Initialize.solution autoYes