{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ApplicativeDo #-}

module Cabal2nix
  ( main, cabal2nix, cabal2nix', cabal2nixWithDB, parseArgs
  , Options(..)
  )
  where

import Control.Exception ( bracket )
import Control.Lens
import Control.Monad
import Data.Maybe ( fromMaybe, isJust )
import qualified Data.Set as Set
import Data.String
import Data.Time
import Distribution.Compiler
import Distribution.Nixpkgs.Fetch
import Distribution.Nixpkgs.Haskell
import Distribution.Nixpkgs.Haskell.FromCabal
import Distribution.Nixpkgs.Haskell.FromCabal.Flags
import Distribution.Nixpkgs.Haskell.Platform
import qualified Distribution.Nixpkgs.Haskell.FromCabal.PostProcess as PP (pkg)
import qualified Distribution.Nixpkgs.Haskell.Hackage as DB
import Distribution.Nixpkgs.Haskell.OrphanInstances ( )
import Distribution.Nixpkgs.Haskell.PackageSourceSpec
import Distribution.Nixpkgs.Meta
import Distribution.Package ( packageId )
import Distribution.PackageDescription ( mkFlagName, mkFlagAssignment, FlagAssignment )
import Distribution.Parsec as P
import Distribution.Simple.Utils ( lowercase )
import Distribution.System
import Language.Nix
import Options.Applicative
import Paths_cabal2nix ( version )
import System.Environment ( getArgs )
import System.IO ( hFlush, hPutStrLn, stdout, stderr )
import qualified Text.PrettyPrint.ANSI.Leijen as P2
import Text.PrettyPrint.HughesPJClass ( Doc, Pretty(..), text, vcat, hcat, semi, render, prettyShow )

{-# ANN module ("HLint: ignore Use Just" :: String) #-}

data Options = Options
  { Options -> Maybe [Char]
optSha256 :: Maybe String
  , Options -> [[Char]]
optMaintainer :: [String]
--, optPlatform :: [String]       -- TODO: fix command line handling of platforms
  , Options -> Bool
optHaddock :: Bool
  , Options -> HpackUse
optHpack :: HpackUse
  , Options -> Bool
optDoCheck :: Bool
  , Options -> Bool
optJailbreak :: Bool
  , Options -> Bool
optDoBenchmark :: Bool
  , Options -> Maybe [Char]
optRevision :: Maybe String
  , Options -> Bool
optHyperlinkSource :: Bool
  , Options -> Bool
optEnableLibraryProfiling :: Bool
  , Options -> Bool
optEnableExecutableProfiling :: Bool
  , Options -> Maybe Bool
optEnableProfiling :: Maybe Bool
  , Options -> [[Char]]
optExtraArgs :: [String]
  , Options -> Maybe [Char]
optHackageDb :: Maybe FilePath
  , Options -> Bool
optNixShellOutput :: Bool
  , Options -> [[Char]]
optFlags :: [String]
  , Options -> CompilerId
optCompiler :: CompilerId
  , Options -> Platform
optSystem :: Platform
  , Options -> Maybe [Char]
optSubpath :: Maybe FilePath
  , Options -> Maybe UTCTime
optHackageSnapshot :: Maybe UTCTime
  , Options -> NixpkgsResolver
optNixpkgsIdentifier :: NixpkgsResolver
  , Options -> [Char]
optUrl :: String
  , Options -> FetchSubmodules
optFetchSubmodules :: FetchSubmodules
  }

options :: Parser Options
options :: Parser Options
options = do
  Maybe [Char]
optSha256
    <- forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (forall s. IsString s => Mod OptionFields s -> Parser s
strOption forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"sha256" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasMetavar f => [Char] -> Mod f a
metavar [Char]
"HASH" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"sha256 hash of source tarball")
  [[Char]]
optMaintainer
    <- forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (forall s. IsString s => Mod OptionFields s -> Parser s
strOption forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"maintainer" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasMetavar f => [Char] -> Mod f a
metavar [Char]
"MAINTAINER" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"maintainer of this package (may be specified multiple times)")
-- optPlatform <- many (strOption $ long "platform" <> metavar "PLATFORM" <> help "supported build platforms (may be specified multiple times)")
  Bool
optHaddock
    <- forall a. a -> a -> Mod FlagFields a -> Parser a
flag Bool
True Bool
False (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"no-haddock" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"don't run Haddock when building this package")
  HpackUse
optHpack
    <-
      (
        forall a. a -> Mod FlagFields a -> Parser a
flag' HpackUse
ForceHpack (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"hpack" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"run hpack before configuring this package (only non-hackage packages)")
        forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
        forall a. a -> Mod FlagFields a -> Parser a
flag' HpackUse
NoHpack (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"no-hpack" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"disable hpack run and use only cabal disregarding package.yaml existence")
        forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
        forall (f :: * -> *) a. Applicative f => a -> f a
pure HpackUse
PackageYamlHpack
      )
  Bool
optDoCheck
    <- forall a. a -> a -> Mod FlagFields a -> Parser a
flag Bool
True Bool
False (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"no-check" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"don't run regression test suites of this package")
  Bool
optJailbreak
    <- Mod FlagFields Bool -> Parser Bool
switch (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"jailbreak" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"disregard version restrictions on build inputs")
  Bool
optDoBenchmark
    <- Mod FlagFields Bool -> Parser Bool
switch (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"benchmark" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"enable benchmarks for this package")
  Maybe [Char]
optRevision
    <- forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (forall s. IsString s => Mod OptionFields s -> Parser s
strOption forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"revision" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"revision to use when fetching from VCS")
  Bool
optHyperlinkSource
    <- forall a. a -> a -> Mod FlagFields a -> Parser a
flag Bool
True Bool
False (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"no-hyperlink-source" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"don't generate pretty-printed source code for the documentation")
  Bool
optEnableLibraryProfiling
    <- Mod FlagFields Bool -> Parser Bool
switch (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"enable-library-profiling" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"enable library profiling in the generated build")
  Bool
optEnableExecutableProfiling
    <- Mod FlagFields Bool -> Parser Bool
switch (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"enable-executable-profiling" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"enable executable profiling in the generated build")
  Maybe Bool
optEnableProfiling
    <- forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Mod FlagFields Bool -> Parser Bool
switch (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"enable-profiling" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"enable both library and executable profiling in the generated build"))
  [[Char]]
optExtraArgs
    <- forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (forall s. IsString s => Mod OptionFields s -> Parser s
strOption forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"extra-arguments" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"extra parameters required for the function body")
  Maybe [Char]
optHackageDb
    <- forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (forall s. IsString s => Mod OptionFields s -> Parser s
strOption forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"hackage-db" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasMetavar f => [Char] -> Mod f a
metavar [Char]
"PATH" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"path to the local hackage db in tar format")
  Bool
optNixShellOutput
    <- Mod FlagFields Bool -> Parser Bool
switch (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"shell" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"generate output suitable for nix-shell")
  [[Char]]
optFlags
    <- forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (forall s. IsString s => Mod OptionFields s -> Parser s
strOption forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'f' forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"flag" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"Cabal flag (may be specified multiple times)")
  CompilerId
optCompiler
    <- forall a. ReadM a -> Mod OptionFields a -> Parser a
option forall a. Parsec a => ReadM a
parseCabal (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"compiler" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"compiler to use when evaluating the Cabal file" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasValue f => a -> Mod f a
value CompilerId
buildCompilerId forall a. Semigroup a => a -> a -> a
<> forall a (f :: * -> *). (a -> [Char]) -> Mod f a
showDefaultWith forall a. Pretty a => a -> [Char]
prettyShow)
  Platform
optSystem
    <- forall a. ReadM a -> Mod OptionFields a -> Parser a
option (forall a. ([Char] -> Maybe a) -> ReadM a
maybeReader [Char] -> Maybe Platform
parsePlatformLenient) (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"system" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"host system (in either short Nix format or full LLVM style) to use when evaluating the Cabal file" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasValue f => a -> Mod f a
value Platform
buildPlatform forall a. Semigroup a => a -> a -> a
<> forall a (f :: * -> *). (a -> [Char]) -> Mod f a
showDefaultWith forall a. Pretty a => a -> [Char]
prettyShow)
  Maybe [Char]
optSubpath
    <- forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (forall s. IsString s => Mod OptionFields s -> Parser s
strOption forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"subpath" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. HasMetavar f => [Char] -> Mod f a
metavar [Char]
"PATH" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"Path to Cabal file's directory relative to the URI (default is root directory)")
  Maybe UTCTime
optHackageSnapshot
    <- forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (forall a. ReadM a -> Mod OptionFields a -> Parser a
option ReadM UTCTime
utcTimeReader (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"hackage-snapshot" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"hackage snapshot time, ISO format"))
  NixpkgsResolver
optNixpkgsIdentifier
    <- forall (f :: * -> *) a. Applicative f => a -> f a
pure (\Identifier
i -> forall a. a -> Maybe a
Just (Iso' Binding (Identifier, Path)
binding forall t b. AReview t b -> b -> t
# (Identifier
i, Iso' Path [Identifier]
path forall t b. AReview t b -> b -> t
# [Iso' Identifier [Char]
ident forall t b. AReview t b -> b -> t
# [Char]
"pkgs", Identifier
i])))
  [Char]
optUrl
    <- forall s. IsString s => Mod ArgumentFields s -> Parser s
strArgument (forall (f :: * -> *) a. HasMetavar f => [Char] -> Mod f a
metavar [Char]
"URI")
  FetchSubmodules
optFetchSubmodules
    <- forall a. a -> a -> Mod FlagFields a -> Parser a
flag FetchSubmodules
FetchSubmodules FetchSubmodules
DontFetchSubmodules  (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"dont-fetch-submodules" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"do not fetch git submodules from git sources")
  pure Options{Bool
[Char]
[[Char]]
Maybe Bool
Maybe [Char]
Maybe UTCTime
CompilerId
Platform
FetchSubmodules
HpackUse
NixpkgsResolver
optFetchSubmodules :: FetchSubmodules
optUrl :: [Char]
optNixpkgsIdentifier :: NixpkgsResolver
optHackageSnapshot :: Maybe UTCTime
optSubpath :: Maybe [Char]
optSystem :: Platform
optCompiler :: CompilerId
optFlags :: [[Char]]
optNixShellOutput :: Bool
optHackageDb :: Maybe [Char]
optExtraArgs :: [[Char]]
optEnableProfiling :: Maybe Bool
optEnableExecutableProfiling :: Bool
optEnableLibraryProfiling :: Bool
optHyperlinkSource :: Bool
optRevision :: Maybe [Char]
optDoBenchmark :: Bool
optJailbreak :: Bool
optDoCheck :: Bool
optHpack :: HpackUse
optHaddock :: Bool
optMaintainer :: [[Char]]
optSha256 :: Maybe [Char]
optFetchSubmodules :: FetchSubmodules
optUrl :: [Char]
optNixpkgsIdentifier :: NixpkgsResolver
optHackageSnapshot :: Maybe UTCTime
optSubpath :: Maybe [Char]
optSystem :: Platform
optCompiler :: CompilerId
optFlags :: [[Char]]
optNixShellOutput :: Bool
optHackageDb :: Maybe [Char]
optExtraArgs :: [[Char]]
optEnableProfiling :: Maybe Bool
optEnableExecutableProfiling :: Bool
optEnableLibraryProfiling :: Bool
optHyperlinkSource :: Bool
optRevision :: Maybe [Char]
optDoBenchmark :: Bool
optJailbreak :: Bool
optDoCheck :: Bool
optHpack :: HpackUse
optHaddock :: Bool
optMaintainer :: [[Char]]
optSha256 :: Maybe [Char]
..}

-- | A parser for the date. Hackage updates happen maybe once or twice a month.
-- Example: parseTime defaultTimeLocale "%FT%T%QZ" "2017-11-20T12:18:35Z" :: Maybe UTCTime
utcTimeReader :: ReadM UTCTime
utcTimeReader :: ReadM UTCTime
utcTimeReader = forall a. ([Char] -> Either [Char] a) -> ReadM a
eitherReader forall a b. (a -> b) -> a -> b
$ \[Char]
arg ->
    case forall (m :: * -> *) t.
(MonadFail m, ParseTime t) =>
Bool -> TimeLocale -> [Char] -> [Char] -> m t
parseTimeM Bool
True TimeLocale
defaultTimeLocale [Char]
"%FT%T%QZ" [Char]
arg of
        Maybe UTCTime
Nothing      -> forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ [Char]
"Cannot parse date, ISO format used ('2017-11-20T12:18:35Z'): " forall a. [a] -> [a] -> [a]
++ [Char]
arg
        Just UTCTime
utcTime -> forall a b. b -> Either a b
Right UTCTime
utcTime

parseCabal :: Parsec a => ReadM a
parseCabal :: forall a. Parsec a => ReadM a
parseCabal = forall a. ([Char] -> Either [Char] a) -> ReadM a
eitherReader forall a. Parsec a => [Char] -> Either [Char] a
eitherParsec

pinfo :: ParserInfo Options
pinfo :: ParserInfo Options
pinfo = forall a. Parser a -> InfoMod a -> ParserInfo a
info
        (   forall a. Parser (a -> a)
helper
        forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall a. [Char] -> Mod OptionFields (a -> a) -> Parser (a -> a)
infoOption ([Char]
"cabal2nix " forall a. [a] -> [a] -> [a]
++ forall a. Pretty a => a -> [Char]
prettyShow Version
version) (forall (f :: * -> *) a. HasName f => [Char] -> Mod f a
long [Char]
"version" forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a. [Char] -> Mod f a
help [Char]
"Show version number")
        forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser Options
options
        )
        (  forall a. InfoMod a
fullDesc
        forall a. Semigroup a => a -> a -> a
<> forall a. [Char] -> InfoMod a
header [Char]
"cabal2nix converts Cabal files into build instructions for Nix."
        forall a. Semigroup a => a -> a -> a
<> forall a. Maybe Doc -> InfoMod a
progDescDoc (forall a. a -> Maybe a
Just ([Doc] -> Doc
P2.vcat
                     [ [Char] -> Doc
P2.text [Char]
""
                     , [Char] -> Doc
P2.text [Char]
"Recognized URI schemes:"
                     , [Char] -> Doc
P2.text [Char]
""
                     , [Char] -> Doc
P2.text [Char]
"  cabal://pkgname-pkgversion     download the specified package from Hackage"
                     , [Char] -> Doc
P2.text [Char]
"  cabal://pkgname                download latest version of this package from Hackage"
                     , [Char] -> Doc
P2.text [Char]
"  file:///local/path             load the Cabal file from the local disk"
                     , [Char] -> Doc
P2.text [Char]
"  /local/path                    abbreviated version of file URI"
                     , [Char] -> Doc
P2.text [Char]
"  <git/svn/bzr/hg URL>           download the source from the specified repository"
                     , [Char] -> Doc
P2.text [Char]
""
                     , [Doc] -> Doc
P2.fillSep (forall a b. (a -> b) -> [a] -> [b]
map [Char] -> Doc
P2.text ([Char] -> [[Char]]
words (  [Char]
"If the URI refers to a cabal file, information for building the package "
                                                      forall a. [a] -> [a] -> [a]
++ [Char]
"will be retrieved from that file, but hackage will be used as a source "
                                                      forall a. [a] -> [a] -> [a]
++ [Char]
"for the derivation. Otherwise, the supplied URI will be used to as the "
                                                      forall a. [a] -> [a] -> [a]
++ [Char]
"source for the derivation and the information is taken from the cabal file "
                                                      forall a. [a] -> [a] -> [a]
++ [Char]
"at the root of the downloaded source."
                                                      )))
                     ]))
        )

main :: IO ()
main :: IO ()
main = forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (forall (m :: * -> *) a. Monad m => a -> m a
return ()) (\() -> Handle -> IO ()
hFlush Handle
stdout forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Handle -> IO ()
hFlush Handle
stderr) forall a b. (a -> b) -> a -> b
$ \() ->
  [[Char]] -> IO ()
cabal2nix forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO [[Char]]
getArgs

hpackOverrides :: Derivation -> Derivation
hpackOverrides :: Derivation -> Derivation
hpackOverrides = forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over Lens' Derivation [Char]
phaseOverrides (forall a. [a] -> [a] -> [a]
++ [Char]
"prePatch = \"hpack\";")
               forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s t a b. ASetter s t a b -> b -> s -> t
set (Lens' Derivation BuildInfo
libraryDepends forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lens' BuildInfo (Set Binding)
tool forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall m. Contains m => Index m -> Lens' m Bool
contains (Identifier -> Binding
PP.pkg Identifier
"hpack")) Bool
True

cabal2nix' :: Options -> IO (Either Doc Derivation)
cabal2nix' :: Options -> IO (Either Doc Derivation)
cabal2nix' opts :: Options
opts@Options{Bool
[Char]
[[Char]]
Maybe Bool
Maybe [Char]
Maybe UTCTime
CompilerId
Platform
FetchSubmodules
HpackUse
NixpkgsResolver
optFetchSubmodules :: FetchSubmodules
optUrl :: [Char]
optNixpkgsIdentifier :: NixpkgsResolver
optHackageSnapshot :: Maybe UTCTime
optSubpath :: Maybe [Char]
optSystem :: Platform
optCompiler :: CompilerId
optFlags :: [[Char]]
optNixShellOutput :: Bool
optHackageDb :: Maybe [Char]
optExtraArgs :: [[Char]]
optEnableProfiling :: Maybe Bool
optEnableExecutableProfiling :: Bool
optEnableLibraryProfiling :: Bool
optHyperlinkSource :: Bool
optRevision :: Maybe [Char]
optDoBenchmark :: Bool
optJailbreak :: Bool
optDoCheck :: Bool
optHpack :: HpackUse
optHaddock :: Bool
optMaintainer :: [[Char]]
optSha256 :: Maybe [Char]
optFetchSubmodules :: Options -> FetchSubmodules
optUrl :: Options -> [Char]
optNixpkgsIdentifier :: Options -> NixpkgsResolver
optHackageSnapshot :: Options -> Maybe UTCTime
optSubpath :: Options -> Maybe [Char]
optSystem :: Options -> Platform
optCompiler :: Options -> CompilerId
optFlags :: Options -> [[Char]]
optNixShellOutput :: Options -> Bool
optHackageDb :: Options -> Maybe [Char]
optExtraArgs :: Options -> [[Char]]
optEnableProfiling :: Options -> Maybe Bool
optEnableExecutableProfiling :: Options -> Bool
optEnableLibraryProfiling :: Options -> Bool
optHyperlinkSource :: Options -> Bool
optRevision :: Options -> Maybe [Char]
optDoBenchmark :: Options -> Bool
optJailbreak :: Options -> Bool
optDoCheck :: Options -> Bool
optHpack :: Options -> HpackUse
optHaddock :: Options -> Bool
optMaintainer :: Options -> [[Char]]
optSha256 :: Options -> Maybe [Char]
..} = do
  Package
pkg <- HpackUse
-> FetchSubmodules
-> Maybe [Char]
-> Maybe UTCTime
-> Source
-> IO Package
getPackage HpackUse
optHpack FetchSubmodules
optFetchSubmodules Maybe [Char]
optHackageDb Maybe UTCTime
optHackageSnapshot forall a b. (a -> b) -> a -> b
$
         Source {
           sourceUrl :: [Char]
sourceUrl = [Char]
optUrl,
           sourceRevision :: [Char]
sourceRevision = forall a. a -> Maybe a -> a
fromMaybe [Char]
"" Maybe [Char]
optRevision,
           sourceHash :: Hash
sourceHash = case Maybe [Char]
optSha256 of
             Maybe [Char]
Nothing -> Hash
UnknownHash
             Just [Char]
hash -> [Char] -> Hash
Guess [Char]
hash,
           sourceCabalDir :: [Char]
sourceCabalDir = forall a. a -> Maybe a -> a
fromMaybe [Char]
"" Maybe [Char]
optSubpath
         }
  Options -> Package -> IO (Either Doc Derivation)
processPackage Options
opts Package
pkg

cabal2nixWithDB :: DB.HackageDB -> Options -> IO (Either Doc Derivation)
cabal2nixWithDB :: HackageDB -> Options -> IO (Either Doc Derivation)
cabal2nixWithDB HackageDB
db opts :: Options
opts@Options{Bool
[Char]
[[Char]]
Maybe Bool
Maybe [Char]
Maybe UTCTime
CompilerId
Platform
FetchSubmodules
HpackUse
NixpkgsResolver
optFetchSubmodules :: FetchSubmodules
optUrl :: [Char]
optNixpkgsIdentifier :: NixpkgsResolver
optHackageSnapshot :: Maybe UTCTime
optSubpath :: Maybe [Char]
optSystem :: Platform
optCompiler :: CompilerId
optFlags :: [[Char]]
optNixShellOutput :: Bool
optHackageDb :: Maybe [Char]
optExtraArgs :: [[Char]]
optEnableProfiling :: Maybe Bool
optEnableExecutableProfiling :: Bool
optEnableLibraryProfiling :: Bool
optHyperlinkSource :: Bool
optRevision :: Maybe [Char]
optDoBenchmark :: Bool
optJailbreak :: Bool
optDoCheck :: Bool
optHpack :: HpackUse
optHaddock :: Bool
optMaintainer :: [[Char]]
optSha256 :: Maybe [Char]
optFetchSubmodules :: Options -> FetchSubmodules
optUrl :: Options -> [Char]
optNixpkgsIdentifier :: Options -> NixpkgsResolver
optHackageSnapshot :: Options -> Maybe UTCTime
optSubpath :: Options -> Maybe [Char]
optSystem :: Options -> Platform
optCompiler :: Options -> CompilerId
optFlags :: Options -> [[Char]]
optNixShellOutput :: Options -> Bool
optHackageDb :: Options -> Maybe [Char]
optExtraArgs :: Options -> [[Char]]
optEnableProfiling :: Options -> Maybe Bool
optEnableExecutableProfiling :: Options -> Bool
optEnableLibraryProfiling :: Options -> Bool
optHyperlinkSource :: Options -> Bool
optRevision :: Options -> Maybe [Char]
optDoBenchmark :: Options -> Bool
optJailbreak :: Options -> Bool
optDoCheck :: Options -> Bool
optHpack :: Options -> HpackUse
optHaddock :: Options -> Bool
optMaintainer :: Options -> [[Char]]
optSha256 :: Options -> Maybe [Char]
..} = do
  forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall a. Maybe a -> Bool
isJust Maybe [Char]
optHackageDb) forall a b. (a -> b) -> a -> b
$ Handle -> [Char] -> IO ()
hPutStrLn Handle
stderr [Char]
"WARN: HackageDB provided directly; ignoring --hackage-db"
  forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall a. Maybe a -> Bool
isJust Maybe UTCTime
optHackageSnapshot) forall a b. (a -> b) -> a -> b
$ Handle -> [Char] -> IO ()
hPutStrLn Handle
stderr [Char]
"WARN: HackageDB provided directly; ignoring --hackage-snapshot"
  Package
pkg <- HpackUse -> FetchSubmodules -> IO HackageDB -> Source -> IO Package
getPackage' HpackUse
optHpack FetchSubmodules
optFetchSubmodules (forall (m :: * -> *) a. Monad m => a -> m a
return HackageDB
db) forall a b. (a -> b) -> a -> b
$
         Source {
           sourceUrl :: [Char]
sourceUrl = [Char]
optUrl,
           sourceRevision :: [Char]
sourceRevision = forall a. a -> Maybe a -> a
fromMaybe [Char]
"" Maybe [Char]
optRevision,
           sourceHash :: Hash
sourceHash = case Maybe [Char]
optSha256 of
             Maybe [Char]
Nothing -> Hash
UnknownHash
             Just [Char]
hash -> [Char] -> Hash
Guess [Char]
hash,
           sourceCabalDir :: [Char]
sourceCabalDir = forall a. a -> Maybe a -> a
fromMaybe [Char]
"" Maybe [Char]
optSubpath
         }
  Options -> Package -> IO (Either Doc Derivation)
processPackage Options
opts Package
pkg

processPackage :: Options -> Package -> IO (Either Doc Derivation)
processPackage :: Options -> Package -> IO (Either Doc Derivation)
processPackage Options{Bool
[Char]
[[Char]]
Maybe Bool
Maybe [Char]
Maybe UTCTime
CompilerId
Platform
FetchSubmodules
HpackUse
NixpkgsResolver
optFetchSubmodules :: FetchSubmodules
optUrl :: [Char]
optNixpkgsIdentifier :: NixpkgsResolver
optHackageSnapshot :: Maybe UTCTime
optSubpath :: Maybe [Char]
optSystem :: Platform
optCompiler :: CompilerId
optFlags :: [[Char]]
optNixShellOutput :: Bool
optHackageDb :: Maybe [Char]
optExtraArgs :: [[Char]]
optEnableProfiling :: Maybe Bool
optEnableExecutableProfiling :: Bool
optEnableLibraryProfiling :: Bool
optHyperlinkSource :: Bool
optRevision :: Maybe [Char]
optDoBenchmark :: Bool
optJailbreak :: Bool
optDoCheck :: Bool
optHpack :: HpackUse
optHaddock :: Bool
optMaintainer :: [[Char]]
optSha256 :: Maybe [Char]
optFetchSubmodules :: Options -> FetchSubmodules
optUrl :: Options -> [Char]
optNixpkgsIdentifier :: Options -> NixpkgsResolver
optHackageSnapshot :: Options -> Maybe UTCTime
optSubpath :: Options -> Maybe [Char]
optSystem :: Options -> Platform
optCompiler :: Options -> CompilerId
optFlags :: Options -> [[Char]]
optNixShellOutput :: Options -> Bool
optHackageDb :: Options -> Maybe [Char]
optExtraArgs :: Options -> [[Char]]
optEnableProfiling :: Options -> Maybe Bool
optEnableExecutableProfiling :: Options -> Bool
optEnableLibraryProfiling :: Options -> Bool
optHyperlinkSource :: Options -> Bool
optRevision :: Options -> Maybe [Char]
optDoBenchmark :: Options -> Bool
optJailbreak :: Options -> Bool
optDoCheck :: Options -> Bool
optHpack :: Options -> HpackUse
optHaddock :: Options -> Bool
optMaintainer :: Options -> [[Char]]
optSha256 :: Options -> Maybe [Char]
..} Package
pkg = do
  let
      withHpackOverrides :: Derivation -> Derivation
      withHpackOverrides :: Derivation -> Derivation
withHpackOverrides = if Package -> Bool
pkgRanHpack Package
pkg then Derivation -> Derivation
hpackOverrides else forall a. a -> a
id

      flags :: FlagAssignment
      flags :: FlagAssignment
flags = PackageIdentifier -> FlagAssignment
configureCabalFlags (forall pkg. Package pkg => pkg -> PackageIdentifier
packageId (Package -> GenericPackageDescription
pkgCabal Package
pkg)) forall a. Monoid a => a -> a -> a
`mappend` [[Char]] -> FlagAssignment
readFlagList [[Char]]
optFlags

      deriv :: Derivation
      deriv :: Derivation
deriv = Derivation -> Derivation
withHpackOverrides forall a b. (a -> b) -> a -> b
$ HaskellResolver
-> NixpkgsResolver
-> Platform
-> CompilerInfo
-> FlagAssignment
-> [Constraint]
-> GenericPackageDescription
-> Derivation
fromGenericPackageDescription (forall a b. a -> b -> a
const Bool
True)
                                            NixpkgsResolver
optNixpkgsIdentifier
                                            Platform
optSystem
                                            (CompilerId -> AbiTag -> CompilerInfo
unknownCompilerInfo CompilerId
optCompiler AbiTag
NoAbiTag)
                                            FlagAssignment
flags
                                            []
                                            (Package -> GenericPackageDescription
pkgCabal Package
pkg)
              forall a b. a -> (a -> b) -> b
& Lens' Derivation DerivationSource
src forall s t a b. ASetter s t a b -> b -> s -> t
.~ Package -> DerivationSource
pkgSource Package
pkg
              forall a b. a -> (a -> b) -> b
& Lens' Derivation [Char]
subpath forall s t a b. ASetter s t a b -> b -> s -> t
.~ forall a. a -> Maybe a -> a
fromMaybe [Char]
"." Maybe [Char]
optSubpath
              forall a b. a -> (a -> b) -> b
& Lens' Derivation Bool
runHaddock forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ (Bool
optHaddock Bool -> Bool -> Bool
&&)
              forall a b. a -> (a -> b) -> b
& Lens' Derivation Bool
jailbreak forall s t a b. ASetter s t a b -> b -> s -> t
.~ Bool
optJailbreak
              forall a b. a -> (a -> b) -> b
& Lens' Derivation Bool
hyperlinkSource forall s t a b. ASetter s t a b -> b -> s -> t
.~ Bool
optHyperlinkSource
              forall a b. a -> (a -> b) -> b
& Lens' Derivation Bool
enableLibraryProfiling forall s t a b. ASetter s t a b -> b -> s -> t
.~ (forall a. a -> Maybe a -> a
fromMaybe Bool
False Maybe Bool
optEnableProfiling Bool -> Bool -> Bool
|| Bool
optEnableLibraryProfiling)
              forall a b. a -> (a -> b) -> b
& Lens' Derivation Bool
enableExecutableProfiling forall s t a b. ASetter s t a b -> b -> s -> t
.~ (forall a. a -> Maybe a -> a
fromMaybe Bool
False Maybe Bool
optEnableProfiling Bool -> Bool -> Bool
|| Bool
optEnableExecutableProfiling)
              forall a b. a -> (a -> b) -> b
& Lens' Derivation Meta
metaSectionforall b c a. (b -> c) -> (a -> b) -> a -> c
.Lens' Meta (Set Identifier)
maintainers forall s t a b. ASetter s t a b -> b -> s -> t
.~ forall a. Ord a => [a] -> Set a
Set.fromList (forall a b. (a -> b) -> [a] -> [b]
map (forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review Iso' Identifier [Char]
ident) [[Char]]
optMaintainer)
--            & metaSection.platforms .~ Set.fromList optPlatform
              forall a b. a -> (a -> b) -> b
& Lens' Derivation Bool
doCheck forall s t. ASetter s t Bool Bool -> Bool -> s -> t
&&~ Bool
optDoCheck
              forall a b. a -> (a -> b) -> b
& Lens' Derivation Bool
doBenchmark forall s t. ASetter s t Bool Bool -> Bool -> s -> t
||~ Bool
optDoBenchmark
              forall a b. a -> (a -> b) -> b
& Lens' Derivation (Set Binding)
extraFunctionArgs forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ forall a. Ord a => Set a -> Set a -> Set a
Set.union (forall a. Ord a => [a] -> Set a
Set.fromList (Binding
"inherit lib"forall a. a -> [a] -> [a]
:forall a b. (a -> b) -> [a] -> [b]
map (forall a. IsString a => [Char] -> a
fromString forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char]
"inherit " forall a. [a] -> [a] -> [a]
++)) [[Char]]
optExtraArgs))

      shell :: Doc
      shell :: Doc
shell = [Doc] -> Doc
vcat
              [ [Char] -> Doc
text [Char]
"{ nixpkgs ? import <nixpkgs> {}, compiler ? \"default\", doBenchmark ? false }:"
              , [Char] -> Doc
text [Char]
""
              , [Char] -> Doc
text [Char]
"let"
              , [Char] -> Doc
text [Char]
""
              , [Char] -> Doc
text [Char]
"  inherit (nixpkgs) pkgs;"
              , [Char] -> Doc
text [Char]
""
              , [Doc] -> Doc
hcat [ [Char] -> Doc
text [Char]
"  f = ", forall a. Pretty a => a -> Doc
pPrint Derivation
deriv, Doc
semi ]
              , [Char] -> Doc
text [Char]
""
              , [Char] -> Doc
text [Char]
"  haskellPackages = if compiler == \"default\""
              , [Char] -> Doc
text [Char]
"                       then pkgs.haskellPackages"
              , [Char] -> Doc
text [Char]
"                       else pkgs.haskell.packages.${compiler};"
              , [Char] -> Doc
text [Char]
""
              , [Char] -> Doc
text [Char]
"  variant = if doBenchmark then pkgs.haskell.lib.doBenchmark else pkgs.lib.id;"
              , [Char] -> Doc
text [Char]
""
              , [Char] -> Doc
text [Char]
"  drv = variant (haskellPackages.callPackage f {});"
              , [Char] -> Doc
text [Char]
""
              , [Char] -> Doc
text [Char]
"in"
              , [Char] -> Doc
text [Char]
""
              , [Char] -> Doc
text [Char]
"  if pkgs.lib.inNixShell then drv.env else drv"
              ]
  forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ if Bool
optNixShellOutput then forall a b. a -> Either a b
Left Doc
shell else forall a b. b -> Either a b
Right Derivation
deriv

cabal2nix :: [String] -> IO ()
cabal2nix :: [[Char]] -> IO ()
cabal2nix = [[Char]] -> IO Options
parseArgs forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> Options -> IO (Either Doc Derivation)
cabal2nix' forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> [Char] -> IO ()
putStrLn forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Doc -> [Char]
render forall a. Pretty a => a -> [Char]
prettyShow

parseArgs :: [String] -> IO Options
parseArgs :: [[Char]] -> IO Options
parseArgs = forall a. ParserResult a -> IO a
handleParseResult forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ParserPrefs -> ParserInfo a -> [[Char]] -> ParserResult a
execParserPure ParserPrefs
defaultPrefs ParserInfo Options
pinfo

-- Utils

readFlagList :: [String] -> FlagAssignment
readFlagList :: [[Char]] -> FlagAssignment
readFlagList = [(FlagName, Bool)] -> FlagAssignment
mkFlagAssignment forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map [Char] -> (FlagName, Bool)
tagWithValue
  where tagWithValue :: [Char] -> (FlagName, Bool)
tagWithValue (Char
'-':[Char]
fname) = ([Char] -> FlagName
mkFlagName ([Char] -> [Char]
lowercase [Char]
fname), Bool
False)
        tagWithValue [Char]
fname       = ([Char] -> FlagName
mkFlagName ([Char] -> [Char]
lowercase [Char]
fname), Bool
True)