Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 16 additions & 13 deletions cabal2nix/hackage2nix/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -152,21 +152,24 @@ main = do
attr :: Identifier
attr = if isInDefaultPackageSet then toNixName name else mangle pkgId

drv :: Derivation
drv = fromGenericPackageDescription haskellResolver nixpkgsResolver targetPlatform (compilerInfo config) flagAssignment [] descr
& src .~ urlDerivationSource ("mirror://hackage/" ++ display pkgId ++ ".tar.gz") tarballSHA256
& editedCabalFile .~ cabalSHA256
-- If a list of platforms is set in the hackage2nix configuration file, prefer that.
-- Otherwise a list defined by PostProcess or Nothing is used.
& metaSection.platforms %~ (Map.lookup name (supportedPlatforms config) <|>)
& metaSection.badPlatforms %~ (Map.lookup name (unsupportedPlatforms config) <|>)
& metaSection.hydraPlatforms %~ (if isHydraEnabled then id else const (Just Set.empty))
& metaSection.broken ||~ isBroken
& metaSection.maintainers .~ Map.findWithDefault Set.empty name globalPackageMaintainers
& metaSection.homepage .~ ""
drv :: FinalizedDerivation
drv = over finalized_derivation modifiers finalized
where
finalized = fromGenericPackageDescription haskellResolver nixpkgsResolver targetPlatform (compilerInfo config) flagAssignment [] descr
modifiers d = d
& src .~ urlDerivationSource ("mirror://hackage/" ++ display pkgId ++ ".tar.gz") tarballSHA256
& editedCabalFile .~ cabalSHA256
-- If a list of platforms is set in the hackage2nix configuration file, prefer that.
-- Otherwise a list defined by PostProcess or Nothing is used.
& metaSection.platforms %~ (Map.lookup name (supportedPlatforms config) <|>)
& metaSection.badPlatforms %~ (Map.lookup name (unsupportedPlatforms config) <|>)
& metaSection.hydraPlatforms %~ (if isHydraEnabled then id else const (Just Set.empty))
& metaSection.broken ||~ isBroken
& metaSection.maintainers .~ Map.findWithDefault Set.empty name globalPackageMaintainers
& metaSection.homepage .~ ""

overrides :: Doc
overrides = fcat $ punctuate space [ pPrint b <> semi | b <- Set.toList (view (dependencies . each) drv `Set.union` view extraFunctionArgs drv), not (isFromHackage b) ]
overrides = fcat $ punctuate space [ pPrint b <> semi | b <- Set.toList (view (finalized_derivation . dependencies . each) drv `Set.union` view (finalized_derivation . extraFunctionArgs) drv), not (isFromHackage b) ]
return $ render $ nest 2 $
hang (pPrint attr <+> equals <+> text "callPackage") 2 (parens (pPrint drv)) <+> (braces overrides <> semi)

Expand Down
29 changes: 17 additions & 12 deletions cabal2nix/src/Cabal2nix.hs
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,9 @@ main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() ->

hpackOverrides :: Derivation -> Derivation
hpackOverrides = over phaseOverrides (++ "prePatch = \"hpack\";")
. set (libraryDepends . tool . contains (PP.pkg "hpack")) True
. set (focusBuildInfo libraryDepends . tool . contains (PP.pkg "hpack")) True

cabal2nix' :: Options -> IO (Either Doc Derivation)
cabal2nix' :: Options -> IO (Either Doc FinalizedDerivation)
cabal2nix' opts@Options{..} = do
pkg <- getPackage optHpack optFetchSubmodules optHackageDb optHackageSnapshot $
Source {
Expand All @@ -190,7 +190,7 @@ cabal2nix' opts@Options{..} = do
}
processPackage opts pkg

cabal2nixWithDB :: DB.HackageDB -> Options -> IO (Either Doc Derivation)
cabal2nixWithDB :: DB.HackageDB -> Options -> IO (Either Doc FinalizedDerivation)
cabal2nixWithDB db opts@Options{..} = do
when (isJust optHackageDb) $ colorStderrLn warningColor "WARN: HackageDB provided directly; ignoring --hackage-db"
when (isJust optHackageSnapshot) $ colorStderrLn warningColor "WARN: HackageDB provided directly; ignoring --hackage-snapshot"
Expand All @@ -205,7 +205,7 @@ cabal2nixWithDB db opts@Options{..} = do
}
processPackage opts pkg

processPackage :: Options -> Package -> IO (Either Doc Derivation)
processPackage :: Options -> Package -> IO (Either Doc FinalizedDerivation)
processPackage Options{..} pkg = do
let
withHpackOverrides :: Derivation -> Derivation
Expand All @@ -219,14 +219,18 @@ processPackage Options{..} pkg = do
Nothing -> pkgSource pkg
Just customExpr -> (pkgSource pkg) { derivCustomSrc = Just customExpr }

deriv :: Derivation
deriv = withHpackOverrides $ fromGenericPackageDescription (const True)
optNixpkgsIdentifier
optSystem
(unknownCompilerInfo optCompiler NoAbiTag)
flags
[]
(pkgCabal pkg)
deriv :: FinalizedDerivation
deriv = over finalized_derivation (withHpackOverrides . modifiers) finalized
where
finalized = fromGenericPackageDescription (const True)
optNixpkgsIdentifier
optSystem
(unknownCompilerInfo optCompiler NoAbiTag)
flags
[]
(pkgCabal pkg)

modifiers d = d
& src .~ finalSource
& subpath .~ fromMaybe "." optSubpath
& runHaddock %~ (optHaddock &&)
Expand All @@ -240,6 +244,7 @@ processPackage Options{..} pkg = do
& doBenchmark ||~ optDoBenchmark
& extraFunctionArgs %~ Set.union (Set.fromList ("inherit lib":map (fromString . ("inherit " ++)) optExtraArgs))


shell :: Doc
shell = vcat
[ text "{ nixpkgs ? import <nixpkgs> {}, compiler ? \"default\", doBenchmark ? false, inNixShell ? false }:"
Expand Down
12 changes: 7 additions & 5 deletions cabal2nix/src/Distribution/Nixpkgs/Haskell/BuildInfo.hs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,11 @@ instance Monoid BuildInfo where
instance NFData BuildInfo

pPrintBuildInfo :: String -> BuildInfo -> Doc
pPrintBuildInfo prefix bi = vcat
[ setattr (prefix++"HaskellDepends") empty (setOf (haskell.folded.localName.ident) bi)
, setattr (prefix++"SystemDepends") empty (setOf (system.folded.localName.ident) bi)
, setattr (prefix++"PkgconfigDepends") empty (setOf (pkgconfig.folded.localName.ident) bi)
, setattr (prefix++"ToolDepends") empty (setOf (tool.folded.localName.ident) bi)
pPrintBuildInfo prefix bi = onlyIf (bi /= mempty) $ vcat
[ pp haskell "HaskellDepends"
, pp system "SystemDepends"
, pp pkgconfig "PkgconfigDepends"
, pp tool "ToolDepends"
]
where
pp fld suffix = setattr (prefix++suffix) empty $ setOf (fld.folded.localName.ident) bi
93 changes: 77 additions & 16 deletions cabal2nix/src/Distribution/Nixpkgs/Haskell/Derivation.hs
Original file line number Diff line number Diff line change
@@ -1,41 +1,63 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}

module Distribution.Nixpkgs.Haskell.Derivation
( Derivation, nullDerivation, pkgid, revision, src, subpath, isLibrary, isExecutable
, extraFunctionArgs, libraryDepends, executableDepends, testDepends, configureFlags
( FinalizedDerivation(..), finalized_compiler, finalized_derivation, finalized_flags, finalized_platform
, Derivation, nullDerivation, pkgid, revision, src, subpath, isLibrary, isExecutable
, Component, Components, extraFunctionArgs, libraryDepends, executableDepends, testDepends, configureFlags
, cabalFlags, runHaddock, jailbreak, doCheck, doBenchmark, testFlags, testTargets, hyperlinkSource
, enableLibraryProfiling, enableExecutableProfiling, phaseOverrides, editedCabalFile, metaSection
, dependencies, setupDepends, benchmarkDepends, enableSeparateDataOutput, extraAttributes
, focusBuildInfo
)
where

import Prelude hiding ((<>))

#if !MIN_VERSION_base(4,18,0)
import Control.Applicative (liftA2)
#endif
import Control.DeepSeq
import Control.Lens
import Data.Foldable
import Data.List ( isPrefixOf )
import Data.Map ( Map )
import qualified Data.Map as Map
import Data.Set ( Set )
import qualified Data.Set as Set
import Data.Set.Lens
import Distribution.Compiler (CompilerInfo)
import Distribution.Nixpkgs.Fetch
import Distribution.Nixpkgs.Haskell.BuildInfo
import Distribution.Nixpkgs.Haskell.OrphanInstances ( )
import Distribution.Nixpkgs.Meta
import Distribution.Package
import Distribution.PackageDescription ( FlagAssignment, unFlagName, unFlagAssignment )
import Distribution.PackageDescription (CondBranch (..), CondTree (..), Condition (..), ConfVar (..), FlagAssignment, FlagName, UnqualComponentName, lookupFlagAssignment, unFlagAssignment, unFlagName)
import Distribution.System (Platform (..))
import GHC.Generics ( Generic )
import Language.Nix
import Language.Nix.PrettyPrinting
import Data.Maybe (fromMaybe)
import Distribution.PackageDescription.Configuration (simplifyWithSysParams)

-- | A represtation of Nix expressions for building Haskell packages.
-- The data type correspond closely to the definition of
-- 'PackageDescription' from Cabal.
data FinalizedDerivation = FinalizedDerivation
{ _finalized_flags :: FlagAssignment
, _finalized_platform :: Platform
, _finalized_compiler :: CompilerInfo
, _finalized_derivation :: Derivation
}

type Components = [(Maybe UnqualComponentName, Component)]
type Component = CondTree ConfVar [Dependency] (BuildInfo, Bool)
data Derivation = MkDerivation
{ _pkgid :: PackageIdentifier
, _revision :: Int
Expand All @@ -46,10 +68,10 @@ data Derivation = MkDerivation
, _extraFunctionArgs :: Set Binding
, _extraAttributes :: Map String String
, _setupDepends :: BuildInfo
, _libraryDepends :: BuildInfo
, _executableDepends :: BuildInfo
, _testDepends :: BuildInfo
, _benchmarkDepends :: BuildInfo
, _libraryDepends :: Components
, _executableDepends :: Components
, _testDepends :: Components
, _benchmarkDepends :: Components
, _configureFlags :: Set String
, _cabalFlags :: FlagAssignment
, _runHaddock :: Bool
Expand Down Expand Up @@ -100,17 +122,26 @@ nullDerivation = MkDerivation
, _metaSection = error "undefined Derivation.metaSection"
}

makeLenses ''FinalizedDerivation

makeLenses ''Derivation

makeLensesFor [("_setupDepends", "dependencies"), ("_libraryDepends", "dependencies"), ("_executableDepends", "dependencies"), ("_testDepends", "dependencies"), ("_benchmarkDepends", "dependencies")] ''Derivation
makeLensesFor (fmap (,"nonSetupDependencies") ["_libraryDepends", "_executableDepends", "_testDepends", "_benchmarkDepends"]) ''Derivation

dependencies :: Traversal' Derivation BuildInfo
dependencies = traversal $ \focus drv ->
liftA2 (set setupDepends) (focus $ view setupDepends drv) ((nonSetupDependencies . traverse . _2 . traverse . _1) focus drv)

focusBuildInfo :: Lens' Derivation Components -> Traversal' Derivation BuildInfo
focusBuildInfo l = l . traverse . _2 . traverse . _1

instance Package Derivation where
packageId = view pkgid

instance NFData Derivation

instance Pretty Derivation where
pPrint drv@MkDerivation {..} = funargs (map text ("mkDerivation" : toAscList inputs)) $$ vcat
instance Pretty FinalizedDerivation where
pPrint (FinalizedDerivation flags (Platform arch os) compiler (MkDerivation {..})) = funargs (map text ("mkDerivation" : toAscList inputs)) $$ vcat
[ text "mkDerivation" <+> lbrace
, nest 2 $ vcat
[ attr "pname" $ doubleQuotes $ pPrint (packageName _pkgid)
Expand All @@ -123,11 +154,11 @@ instance Pretty Derivation where
, boolattr "isLibrary" (not _isLibrary || _isExecutable) _isLibrary
, boolattr "isExecutable" (not _isLibrary || _isExecutable) _isExecutable
, boolattr "enableSeparateDataOutput" _enableSeparateDataOutput _enableSeparateDataOutput
, onlyIf (_setupDepends /= mempty) $ pPrintBuildInfo "setup" _setupDepends
, onlyIf (_libraryDepends /= mempty) $ pPrintBuildInfo "library" _libraryDepends
, onlyIf (_executableDepends /= mempty) $ pPrintBuildInfo "executable" _executableDepends
, onlyIf (_testDepends /= mempty) $ pPrintBuildInfo "test" _testDepends
, onlyIf (_benchmarkDepends /= mempty) $ pPrintBuildInfo "benchmark" _benchmarkDepends
, pPrintBuildInfo "setup" _setupDepends
, pPrintBuildInfo "library" lib
, pPrintBuildInfo "executable" exe
, pPrintBuildInfo "test" test
, pPrintBuildInfo "benchmark" bench
, boolattr "enableLibraryProfiling" _enableLibraryProfiling _enableLibraryProfiling
, boolattr "enableExecutableProfiling" _enableExecutableProfiling _enableExecutableProfiling
, boolattr "doHaddock" (not _runHaddock) _runHaddock
Expand All @@ -146,14 +177,44 @@ instance Pretty Derivation where
where
inputs :: Set String
inputs = Set.unions [ Set.map (view (localName . ident)) _extraFunctionArgs
, setOf (dependencies . each . folded . localName . ident) drv
, setOf (each . folded . localName . ident) $ fold [_setupDepends, lib, exe, test, bench]
, case derivKind _src of
Nothing -> mempty
Just derivKind' -> Set.fromList [derivKindFunction derivKind' | not isHackagePackage]
]

(lib, exe, test, bench) = over each (foldMap $ eval . snd)
(_libraryDepends, _executableDepends, _testDepends, _benchmarkDepends)

renderedFlags = [ text "-f" <> (if enable then empty else char '-') <> text (unFlagName f) | (f, enable) <- unFlagAssignment _cabalFlags ]
++ map text (toAscList _configureFlags)
isHackagePackage = "mirror://hackage/" `isPrefixOf` derivUrl _src

postUnpack = string $ "sourceRoot+=/" ++ _subpath ++ "; echo source root reset to $sourceRoot"

eval :: Component -> BuildInfo
eval = fold . evalTree

evalTree :: Component -> Maybe BuildInfo
evalTree (CondNode (bi, buildable) _ branches) = case buildable of
False -> Nothing
True -> do
bs <- traverse evalBranch branches
pure $ fold $ bi : bs

evalBranch :: CondBranch ConfVar [Dependency] (BuildInfo, Bool) -> Maybe BuildInfo
evalBranch (CondBranch c t mf) =
if evalCondition c
then evalTree t
else maybe (Just mempty) evalTree mf

evalCondition :: Condition ConfVar -> Bool
evalCondition = go . fst . simplifyWithSysParams os arch compiler
where
go :: Condition FlagName -> Bool
go = \case
Lit b -> b
CNot c -> not $ go c
COr a b -> go a || go b
CAnd a b -> go a && go b
Var fn -> fromMaybe False $ lookupFlagAssignment fn flags
Loading
Loading