packages feed

elm2nix-0.5.0: src/Elm2Nix.hs

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}

module Elm2Nix
  ( convert,
    initialize,
    snapshot,
  )
where

import Control.Concurrent.Async (mapConcurrently)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Trans.Except (ExceptT, runExceptT, throwE)
import Data.List (intercalate)
import Data.String.Here
import Data.Text (Text)
import qualified Data.Text as Text
import Elm2Nix.ElmJson (Elm2NixError (..), readElmJson, toErrorMessage)
import Elm2Nix.FixedOutput (FixedDerivation (..), prefetch)
import Elm2Nix.PackagesSnapshot (snapshot)
import Prettyprinter (Doc, Pretty (..), align, braces, defaultLayoutOptions, dquotes, equals, layoutPretty, line, nest, punctuate, semi, vsep)
import Prettyprinter.Render.String (renderString)
import System.Exit (exitFailure)
import System.IO (hPutStrLn, stderr)

newtype Elm2Nix a = Elm2Nix {runElm2Nix_ :: ExceptT Elm2NixError IO a}
  deriving (Functor, Applicative, Monad, MonadIO)

runElm2Nix :: Elm2Nix a -> IO (Either Elm2NixError a)
runElm2Nix = runExceptT . runElm2Nix_

throwErr :: Elm2NixError -> Elm2Nix a
throwErr e = Elm2Nix (throwE e)

-- CMDs

convert :: IO ()
convert = runCLI $ do
  liftIO (hPutStrLn stderr "Resolving elm.json dependencies into Nix ...")

  deps <- either throwErr return =<< liftIO (readElmJson "elm.json")
  liftIO (hPutStrLn stderr "Prefetching tarballs and computing sha256 hashes ...")

  sources <- liftIO (mapConcurrently (uncurry prefetch) deps)
  liftIO (putStrLn (generateNixSources sources))

initialize :: IO ()
initialize =
  runCLI $
    liftIO (putStrLn [template|data/default.nix|])
  where
    -- \| Converts Package.Name to Nix friendly name
    baseName :: Text
    baseName = "elm-app"
    version :: Text
    version = "0.1.0"
    toNixName :: Text -> Text
    toNixName = Text.replace "/" "-"
    name :: String
    name = Text.unpack (toNixName baseName <> "-" <> version)
    srcdir :: String
    srcdir = "./src" -- TODO: get from elm.json

-- Utils

runCLI :: Elm2Nix a -> IO a
runCLI m = do
  result <- runElm2Nix m
  case result of
    Right a ->
      return a
    Left err -> do
      depErrToStderr err
      exitFailure

depErrToStderr :: Elm2NixError -> IO ()
depErrToStderr = hPutStrLn stderr . toErrorMessage

generateNixSources :: [FixedDerivation] -> String
generateNixSources dss = renderString (layoutPretty defaultLayoutOptions (nixSources dss))
  where
    nixSources :: [FixedDerivation] -> Doc ann
    nixSources drvs = braces (nest 2 (line <> vsep entries) <> line)
      where
        entries = map nixEntry drvs

    nixEntry :: FixedDerivation -> Doc ann
    nixEntry drv =
      dquotes (pretty (drvName drv)) <> " = " <> braces (nest 2 (line <> attrs) <> line) <> semi
      where
        attrs =
          vsep
            [ "sha256 = " <> dquotes (pretty (drvHash drv)) <> semi,
              "version = " <> dquotes (pretty (drvVersion drv)) <> semi
            ]