packages feed

stackage2nix 0.3.0 → 0.4.0

raw patch · 15 files changed

+371/−169 lines, 15 filesdep ~inflectionsnew-uploader

Dependency ranges changed: inflections

Files

CHANGELOG.md view
@@ -2,3 +2,9 @@  - Initial Hackage release - Add CHANGELOG.md++# 0.4.0+- Add `--resolver` option to generate full stackage packages set+- Add Nix wrapper, see `nix/README.md`+- Upd support cabal2nix >2.5+- Fix honor `--hackage-db` flag
README.md view
@@ -5,7 +5,47 @@ `stackage2nix` converts a Stack file into a Nix Haskell packages set. It creates LTS Stackage packages set, and applies appropriate overrides on top of it. +## Install++You can install `stackage2nix` from the Nix expression:+ ```+nix-env -i -f ./nix/stackage2nix+```++It provides pre-configured wrapper around the raw executable with runtime+`PATH` and all auxiliary flags set up.++## Build project++Generate derivations from `stack.yaml` config using Nix wrapper:++``` bash+stackage2nix ./stack.yaml+```++if you're using the raw executable, you should supply additional flags. See+section 'Flags' below for details.++This command will result in a Haskell packages set, similar to+`pkgs.haskell.packages.<compiler>`, containing only packages that are required+to build targets listed in `stackage.yaml`. To build a package run:++``` bash+nix-build -A my-package+```++## Build stackage++Generate complete Stackage packages set from resolver:++``` bash+stackage2nix --resolver lts-9.0+```++## Flags++``` stackage2nix \   --lts-haskell "$LTS_HASKELL_REPO" \   --all-cabal-hashes "$ALL_CABAL_HASHES_REPO" \@@ -28,12 +68,15 @@ nix-build -A <package-name> ``` +See also the [blog post](https://blog.typeable.io/posts/2017-08-24-stackage2nix.html)+about history and motivation behind the project.+ ## Runtime dependencies  - `nix-env` is required to be on PATH by the   [distribution-nixpkgs](https://hackage.haskell.org/package/distribution-nixpkgs)   dependency-- `nix-prefetch-git` is required on PATH if you have git dependencies in+- `nix-prefetch-scripts` is required on PATH if you have git dependencies in   `stack.yaml`  ## Override result derivation@@ -59,8 +102,13 @@  For more complex overrides and detailed information on how to work with Haskell packages in Nix, see Nixpkgs manual [User’s Guide to the Haskell Infrastructure](http://nixos.org/nixpkgs/manual/#users-guide-to-the-haskell-infrastructure) +## Tests -## Examples+Integration tests that build stackage2nix form different stack configs: -For other examples of `stackage2nix` usage, see [4e6/stackage2nix-examples](https://github.com/4e6/stackage2nix-examples) repository.-It verifies `stackage2nix` by running it on different public projects.+```+STACKAGE_REPO=<path/to/stackage/repo> \+ALL_CABAL_HASHES=<path/to/all-cabal-hashes/repo> \+STACK_FILE=stack-ghc-7103.yaml \+./ci-stackage2nix+```
src/Distribution/Nixpkgs/Haskell/FromStack.hs view
@@ -26,19 +26,22 @@   , targetCompiler  :: CompilerInfo }  data PackageConfig = PackageConfig-  { enableCheck   :: Bool-  , enableHaddock :: Bool }+  { enableCheck     :: Bool+  , enableHaddock   :: Bool }  removeTests :: GenericPackageDescription -> GenericPackageDescription removeTests gd = gd { condTestSuites = [] } +removeBenches :: GenericPackageDescription -> GenericPackageDescription+removeBenches gd = gd { condBenchmarks = [] }+ planDependencies :: PackagePlan -> [Dependency] planDependencies = map makeDependency . Map.toList . sdPackages . ppDesc  where   makeDependency (name, depInfo) = Dependency name (diRange depInfo) -buildNodeM :: PackageSetConfig -> PackageConfig -> PackageName -> PackagePlan -> IO Node-buildNodeM conf pconf name plan = do+buildNode :: PackageSetConfig -> PackageConfig -> PackageName -> PackagePlan -> IO Node+buildNode conf pconf name plan = do   let     cabalHashes = maybe mempty cfiHashes $ ppCabalFileInfo plan     mGitSha1 = Map.lookup "GitSHA1" cabalHashes@@ -50,15 +53,16 @@   let     constraints = ppConstraints plan     testsEnabled =-      enableCheck pconf &&       pcTests constraints == ExpectSuccess     haddocksEnabled =-      enableHaddock pconf &&       pcHaddocks constraints == ExpectSuccess &&       not (Set.null (sdModules (ppDesc plan)))     configureTests       | pcTests constraints == Don'tBuild = removeTests       | otherwise = id+    configureBenches+      | pcBenches constraints == Don'tBuild = removeBenches+      | otherwise = id     flags = Map.toList (pcFlagOverrides constraints)     (descr, missingDeps) = finalizeGenericPackageDescription       (haskellResolver conf)@@ -66,7 +70,7 @@       (targetCompiler conf)       flags       (planDependencies plan)-      (configureTests (pkgCabal pkg))+      (configureBenches . configureTests $ pkgCabal pkg)     genericDrv = fromPackageDescription       (haskellResolver conf)       (nixpkgsResolver conf)@@ -83,11 +87,14 @@       testsEnabled &&       not (null missingDeps) &&       setOf (folded . to depName) missingDeps `hasIntersection` testDeps descr-  in-    genericDrv-      & src .~ pkgSource pkg+  in finalizePackage pkg pconf+    $ genericDrv       & doCheck .~ testsEnabled       & runHaddock .~ haddocksEnabled       & metaSection . Nix.broken .~ brokenEnabled-      -- TODO: remove after Nixos/Nixpkgs #27196 released-      & enableSeparateDataOutput .~ False++finalizePackage :: Package -> PackageConfig -> Derivation -> Derivation+finalizePackage pkg pconf drv = drv+  & src .~ pkgSource pkg+  & doCheck &&~ enableCheck pconf+  & runHaddock &&~ enableHaddock pconf
src/Distribution/Nixpkgs/Haskell/FromStack/Package.hs view
@@ -1,8 +1,9 @@ module Distribution.Nixpkgs.Haskell.FromStack.Package where  import Control.Lens-import Data.Graph (Graph, Vertex) import Data.Foldable as F+import Data.Function (on)+import Data.Graph (Graph, Vertex) import Data.Maybe import Data.Monoid import Data.Ord as O@@ -21,12 +22,21 @@ import qualified Data.Set as Set  data Node = Node-  { _nodeDerivation   :: Derivation-  , _nodeTestDepends  :: Set.Set String-  , _nodeOtherDepends :: Set.Set String }+  { _nodeDerivation        :: Derivation+  , _nodeTestDepends       :: Set.Set String+  , _nodeBenchmarkDepends  :: Set.Set String+  , _nodeExecutableDepends :: Set.Set String+  , _nodeSetupDepends      :: Set.Set String+  , _nodeOtherDepends      :: Set.Set String }  makeLenses ''Node +instance Eq Node where+  (==) = (==) `on` nodeName++instance Ord Node where+  compare = compare `on` nodeName+ mkNode :: Derivation -> Node mkNode _nodeDerivation = Node{..}   where@@ -34,17 +44,27 @@       . Set.filter isFromHackage       $ view (s . (haskell <> tool)) _nodeDerivation     _nodeTestDepends = haskellDependencies testDepends+    _nodeBenchmarkDepends = haskellDependencies benchmarkDepends+    _nodeExecutableDepends = haskellDependencies executableDepends+    _nodeSetupDepends = haskellDependencies setupDepends     _nodeOtherDepends = haskellDependencies (executableDepends <> libraryDepends)  nodeName :: Node -> String nodeName = unPackageName . packageName . view (nodeDerivation . pkgid) +nodeCycleDepends :: Node -> Set.Set String+nodeCycleDepends = _nodeTestDepends <> _nodeOtherDepends+ nodeDepends :: Node -> Set.Set String-nodeDepends = _nodeTestDepends <> _nodeOtherDepends+nodeDepends = _nodeTestDepends+  <> _nodeOtherDepends+  <> _nodeBenchmarkDepends+  <> _nodeExecutableDepends+  <> _nodeSetupDepends  findCycles :: [Node] -> [[Node]] findCycles nodes = mapMaybe cyclic $-  Graph.stronglyConnComp [(node, nodeName node, Set.toList $ nodeDepends node) | node <- nodes]+  Graph.stronglyConnComp [(node, nodeName node, Set.toList $ nodeCycleDepends node) | node <- nodes]  where   cyclic (Graph.AcyclicSCC _) = Nothing   cyclic (Graph.CyclicSCC c)  = Just c@@ -68,12 +88,13 @@ buildNodeGraph nodes = Graph.graphFromEdges   [(node, nodeName node, Set.toList $ nodeDepends node) | node <- nodes] -reachableDependencies :: [Node] -> [Node] -> [Node]-reachableDependencies keyNodes nodes = view _1 . fromVertex <$> reachableVertices+reachableDependencies :: [Node] -> [Node] -> Set.Set Node+reachableDependencies keyNodes nodes = Set.map (view _1 . fromVertex) reachableVerticesS   where     (graph, fromVertex, fromKey) = buildNodeGraph nodes     keys = mapMaybe (fromKey . nodeName) keyNodes-    reachableVertices = concatMap F.toList $ Graph.dfs graph keys+    reachableVerticesS = F.foldr1 Set.union+      $ (Set.fromList . F.toList) <$> Graph.dfs graph keys  -- pretty printing @@ -85,9 +106,9 @@  pPrintOutConfig :: SystemInfo -> [Node] -> Doc pPrintOutConfig systemInfo nodes = vcat-  [ "{ pkgs }:"+  [ "{ pkgs, haskellLib }:"   , ""-  , "with pkgs.haskell.lib; self: super: {"+  , "with haskellLib; self: super: {"   , ""   , "  # core packages"   , nest 2 $ vcat $
src/Distribution/Nixpkgs/Haskell/Stack.hs view
@@ -1,11 +1,14 @@+{-# LANGUAGE CPP #-} module Distribution.Nixpkgs.Haskell.Stack where  import Control.Lens+import Data.Maybe (fromMaybe) import Data.Text as T import Distribution.Compiler as Compiler import Distribution.Nixpkgs.Fetch import Distribution.Nixpkgs.Haskell.Derivation import Distribution.Nixpkgs.Haskell.FromCabal as FromCabal+import Distribution.Nixpkgs.Haskell.FromStack as FromStack import Distribution.Nixpkgs.Haskell.PackageSourceSpec as PackageSourceSpec import Distribution.PackageDescription as PackageDescription import Distribution.System as System@@ -40,32 +43,46 @@   -> StackPackage   -> IO Package getStackPackageFromDb optHackageDb stackPackage =+#if MIN_VERSION_cabal2nix(2,6,0)   PackageSourceSpec.getPackage+    False     (unHackageDb <$> optHackageDb)-    (stackLocationToSource $ stackPackage ^. spLocation)+    Nothing+    (stackLocationToSource (stackPackage ^. spLocation) (stackPackage ^. spDir))+#else+  PackageSourceSpec.getPackage+    (unHackageDb <$> optHackageDb)+    (stackLocationToSource (stackPackage ^. spLocation) (stackPackage ^. spDir))+#endif -stackLocationToSource :: PackageLocation -> Source-stackLocationToSource = \case+stackLocationToSource+  :: PackageLocation+     -- ^ Subdirectory in the package containing cabal file.+  -> Maybe FilePath+  -> Source+stackLocationToSource pl mCabalDir = case pl of   HackagePackage p -> Source     { sourceUrl      = "cabal://" ++ T.unpack p     , sourceRevision = mempty     , sourceHash     = UnknownHash-    , sourceCabalDir = mempty }+    , sourceCabalDir = cabalDir }   StackFilePath p  -> Source     { sourceUrl      = p     , sourceRevision = mempty     , sourceHash     = UnknownHash-    , sourceCabalDir = mempty }+    , sourceCabalDir = cabalDir }   StackUri uri     -> Source     { sourceUrl      = URI.uriToString id uri mempty     , sourceRevision = mempty     , sourceHash     = UnknownHash-    , sourceCabalDir = mempty }+    , sourceCabalDir = cabalDir }   StackRepo r      -> Source     { sourceUrl      = T.unpack $ r ^. rUri     , sourceRevision = T.unpack $ r ^. rCommit     , sourceHash     = UnknownHash-    , sourceCabalDir = mempty }+    , sourceCabalDir = cabalDir }+  where+    cabalDir = fromMaybe mempty mCabalDir  packageDerivation   :: StackPackagesConfig@@ -76,16 +93,12 @@   pkg <- getStackPackageFromDb optHackageDb stackPackage   let     drv = genericPackageDerivation conf pkg-      & src .~ pkgSource pkg-      -- TODO: remove after Nixos/Nixpkgs #27196 released-      & enableSeparateDataOutput .~ False-  return $ if stackPackage ^. spExtraDep-    then drv-      & doCheck &&~ conf ^. spcDoCheckStackage-      & runHaddock &&~ conf ^. spcDoHaddockStackage-    else drv-      & doCheck &&~ conf ^. spcDoCheckPackages-      & runHaddock &&~ conf ^. spcDoHaddockPackages+      & subpath %~ flip fromMaybe (stackPackage ^. spDir)+    isExtraDep = stackPackage ^. spExtraDep+    pconf = PackageConfig+      { enableCheck = if isExtraDep then conf ^. spcDoCheckStackage else conf ^. spcDoCheckPackages+      , enableHaddock = if isExtraDep then conf ^. spcDoHaddockStackage else conf ^. spcDoHaddockPackages }+  return $ finalizePackage pkg pconf drv  genericPackageDerivation   :: StackPackagesConfig
src/Distribution/Nixpkgs/Haskell/Stack/PrettyPrinting.hs view
@@ -42,15 +42,11 @@  importStackagePackages :: FilePath -> Doc importStackagePackages path = hsep-  [ funarg "self",  "import", disp (fromString path :: Nix.FilePath), "{"-  , "inherit pkgs stdenv;"-  , "inherit (self) callPackage;"-  , "}"-  ]+  ["import", disp (fromString path :: Nix.FilePath)] -callStackageConfig :: FilePath -> Doc-callStackageConfig path = hsep-  [ "callPackage", disp (fromString path :: Nix.FilePath), "{}"]+importStackageConfig :: FilePath -> Doc+importStackageConfig path = hsep+  ["import ", disp (fromString path :: Nix.FilePath), "{ inherit pkgs haskellLib; }"]  overrideHaskellPackages :: OverrideConfig -> NonEmpty Derivation -> Doc overrideHaskellPackages oc packages =@@ -67,8 +63,9 @@   , "let"   , nest 2 "inherit (stdenv.lib) extends;"   , nest 2 $ vcat-    [ attr "stackagePackages" . importStackagePackages $ oc ^. ocStackagePackages-    , attr "stackageConfig" . callStackageConfig $ oc ^. ocStackageConfig ]+    [ attr "haskellLib" "callPackage (nixpkgs.path + \"/pkgs/development/haskell-modules/lib.nix\") {}"+    , attr "stackagePackages" . importStackagePackages $ oc ^. ocStackagePackages+    , attr "stackageConfig" . importStackageConfig $ oc ^. ocStackageConfig ]   , nest 2 $ vcat     [ "stackPackages ="     , nest 2 $ overridePackages packages <> semi@@ -82,8 +79,36 @@   , "in callPackage (nixpkgs.path + \"/pkgs/development/haskell-modules\") {"   , nest 2 $ vcat     [ attr "ghc" ("pkgs.haskell.compiler." <> toNixGhcVersion (oc ^. ocGhc))-    , attr "compilerConfig" "self: extends pkgOverrides (extends stackageConfig (stackagePackages self))"-    , attr "haskellLib" "callPackage (nixpkgs.path + \"/pkgs/development/haskell-modules/lib.nix\") {}"+    , attr "compilerConfig" "self: extends pkgOverrides (stackageConfig self)"+    , attr "initialPackages" "stackagePackages"+    , attr "configurationCommon" "args: self: super: {}"+    , "inherit haskellLib;"+    ]+  , "}"+  ]++pPrintHaskellPackages :: OverrideConfig -> Doc+pPrintHaskellPackages oc =+  let+    nixpkgs = if oc ^. ocNixpkgs . to fromString == systemNixpkgs+      then systemNixpkgs+      else (disp . (fromString :: FilePath -> Nix.FilePath)) (oc ^. ocNixpkgs)+  in vcat+  [ funargs+    [ "nixpkgs ? import " <> nixpkgs <> " {}"+    ]+  , ""+  , "with nixpkgs; let"+  , nest 2 $ vcat+    [ attr "haskellLib" "callPackage (nixpkgs.path + /pkgs/development/haskell-modules/lib.nix) {}"+    ]+  , "in callPackage (nixpkgs.path + /pkgs/development/haskell-modules) {"+  , nest 2 $ vcat+    [ attr "ghc" ("pkgs.haskell.compiler." <> toNixGhcVersion (oc ^. ocGhc))+    , attr "compilerConfig" . importStackageConfig $ oc ^. ocStackageConfig+    , attr "initialPackages" . importStackagePackages $ oc ^. ocStackagePackages+    , attr "configurationCommon" "if builtins.pathExists ./configuration-common.nix then import ./configuration-common.nix else args: self: super: {}"+    , "inherit haskellLib;"     ]   , "}"   ]
src/Language/Nix/FilePath.hs view
@@ -11,7 +11,7 @@ import           Distribution.Text import           GHC.Generics (Generic) import           Prelude hiding (FilePath)-import qualified System.FilePath.Posix as Posix+import qualified System.FilePath as FP import           Test.QuickCheck as QC import           Text.PrettyPrint as PP @@ -25,7 +25,7 @@   rnf = rnf . unFilePath  instance Arbitrary FilePath where-  arbitrary = FilePath <$> QC.suchThat arbitrary Posix.isValid+  arbitrary = FilePath <$> QC.suchThat arbitrary FP.isValid   shrink = fmap FilePath . shrink . unFilePath  instance Text FilePath where@@ -38,12 +38,12 @@ parseFilePath :: ReadP r FilePath parseFilePath = do   path <- ReadP.munch (const True)-  if Posix.isValid path+  if FP.isValid path     then pure (FilePath path)     else pfail  renderFilePath :: FilePath -> String-renderFilePath = Posix.combine "."-               . Posix.normalise-               . Posix.dropTrailingPathSeparator+renderFilePath = FP.combine "."+               . FP.normalise+               . FP.dropTrailingPathSeparator                . unFilePath
src/LtsHaskell.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} module LtsHaskell where  import AllCabalHashes@@ -46,17 +47,21 @@       (error (display pkgId ++ ": meta data has no SHA256 hash for the tarball"))       (view (mHashes . at "SHA256") meta)     source = DerivationSource "url" ("mirror://hackage/" ++ display pkgId ++ ".tar.gz") "" tarballSHA256+#if MIN_VERSION_cabal2nix(2,6,0)+  return $ Package source False pkgDesc+#else   return $ Package source pkgDesc+#endif -getPackageFromDb :: PackageIdentifier -> IO Package-getPackageFromDb pkgId =-  getStackPackageFromDb Nothing-  $ StackPackage (HackagePackage (T.pack $ Text.display pkgId)) True+getPackageFromDb :: Maybe HackageDb -> PackageIdentifier -> IO Package+getPackageFromDb mHackageDb pkgId =+  getStackPackageFromDb mHackageDb+  $ StackPackage (HackagePackage (T.pack $ Text.display pkgId)) True Nothing -loadPackage :: FilePath -> Maybe SHA1Hash -> PackageIdentifier -> IO Package-loadPackage allCabalHashesPath mSha1Hash pkgId =+loadPackage :: Maybe HackageDb -> FilePath -> Maybe SHA1Hash -> PackageIdentifier -> IO Package+loadPackage mHackageDb allCabalHashesPath mSha1Hash pkgId =   getPackageFromRepo allCabalHashesPath mSha1Hash pkgId-  `catchIOError` const (getPackageFromDb pkgId)+  `catchIOError` const (getPackageFromDb mHackageDb pkgId)  ghcCompilerInfo :: Version -> CompilerInfo ghcCompilerInfo v = CompilerInfo@@ -72,17 +77,18 @@   maybe False (`withinRange` versionRange) $ Map.lookup depName packageVersions  buildPackageSetConfig-  :: FilePath+  :: Maybe HackageDb   -> FilePath+  -> FilePath   -> BuildPlan   -> IO PackageSetConfig-buildPackageSetConfig optAllCabalHashes optNixpkgsRepository buildPlan = do+buildPackageSetConfig mHackageDb optAllCabalHashes optNixpkgsRepository buildPlan = do   nixpkgs <- readNixpkgPackageMap optNixpkgsRepository Nothing   let     systemInfo      = bpSystemInfo buildPlan     packageVersions = fmap ppVersion (bpPackages buildPlan) `Map.union` siCorePackages systemInfo   return PackageSetConfig-    { packageLoader   = loadPackage optAllCabalHashes+    { packageLoader   = loadPackage mHackageDb optAllCabalHashes     , targetPlatform  = Platform (siArch systemInfo) (siOS systemInfo)     , targetCompiler  = ghcCompilerInfo (siGhcVersion systemInfo)     , nixpkgsResolver = resolve (Map.map (Set.map (over path ("pkgs":))) nixpkgs)
src/Runner.hs view
@@ -2,7 +2,7 @@  import Control.Lens import Data.Foldable as F-import Data.Functor+import Data.List as L import Distribution.Nixpkgs.Haskell.FromStack import Distribution.Nixpkgs.Haskell.FromStack.Package import Distribution.Nixpkgs.Haskell.Stack@@ -18,8 +18,8 @@ import Stack.Config import Stack.Types import Stackage.Types-import System.IO (withFile, IOMode(..), hPutStrLn, hPrint)-import Text.PrettyPrint.HughesPJClass (render)+import System.IO (withFile, IOMode(..), hPutStrLn)+import Text.PrettyPrint.HughesPJClass (Doc, render)  import qualified Data.Set as Set import qualified Data.Map as Map@@ -29,60 +29,92 @@ run :: IO () run = do   opts <- execParser pinfo-  stackYaml <- envStackYaml >>= \case-    Just p  -> putStrLn "Getting project config file from STACK_YAML environment" $> p-    Nothing -> pure $ opts ^. optStackYaml-  stackConf <- either fail pure =<< readStackConfig stackYaml-  let buildPlanFile = LH.buildPlanFilePath (opts ^. optLtsHaskellRepo) (stackConf ^. scResolver)-  buildPlan <- LH.loadBuildPlan buildPlanFile-  packageSetConfig <- LH.buildPackageSetConfig-    (opts ^. optAllCabalHashesRepo)-    (opts ^. optNixpkgsRepository)-    buildPlan-  -- generate haskell packages override-  let-    overrideConfig = mkOverrideConfig opts (siGhcVersion $ bpSystemInfo buildPlan)-    stackPackagesConfig = mkStackPackagesConfig opts-  packages <- traverse (packageDerivation stackPackagesConfig (opts ^. optHackageDb))-    $ stackConf ^. scPackages-  let out = PP.overrideHaskellPackages overrideConfig packages-  withFile (opts ^. optOutDerivation) WriteMode $ \h -> do-    hPutStrLn h ("# Generated by stackage2nix " ++ Text.display version ++ " from " ++ stackYaml ^. syFilePath)-    hPrint h out-  let-    reachable = Set.map mkPackageName-      $ F.foldr1 Set.union-      $ nodeDepends . mkNode <$> packages-    s2nLoader mHash pkgId =-      if pkgName pkgId `Set.member` reachable-      then packageLoader packageSetConfig Nothing pkgId-      else packageLoader packageSetConfig mHash pkgId-    s2nPackageSetConfig = packageSetConfig { packageLoader = s2nLoader }-    s2nPackageConfig = PackageConfig-      { enableCheck   = opts ^. optDoCheckStackage-      , enableHaddock = opts ^. optDoHaddockStackage }-  allNodes <- traverse (uncurry (buildNodeM s2nPackageSetConfig s2nPackageConfig))-    $ Map.toList (bpPackages buildPlan)+  case opts ^. optConfigOrigin of+    -- Generate build derivation from stack.yaml file+    OriginStackYaml stackYaml -> do+      stackConf <- either fail pure =<< readStackConfig stackYaml+      let buildPlanFile = LH.buildPlanFilePath (opts ^. optLtsHaskellRepo) (stackConf ^. scResolver)+      buildPlan <- LH.loadBuildPlan buildPlanFile+      packageSetConfig <- LH.buildPackageSetConfig+        (opts ^. optHackageDb)+        (opts ^. optAllCabalHashesRepo)+        (opts ^. optNixpkgsRepository)+        buildPlan+      let+        overrideConfig = mkOverrideConfig opts (siGhcVersion $ bpSystemInfo buildPlan)+        stackPackagesConfig = mkStackPackagesConfig opts+      stackConfPackages <- traverse (packageDerivation stackPackagesConfig (opts ^. optHackageDb))+        $ stackConf ^. scPackages+      let+        reachable = Set.map mkPackageName+          $ F.foldr1 Set.union+          $ nodeDepends . mkNode <$> stackConfPackages+        s2nLoader mHash pkgId =+          if pkgName pkgId `Set.member` reachable+          then packageLoader packageSetConfig Nothing pkgId+          else packageLoader packageSetConfig mHash pkgId+        s2nPackageSetConfig = packageSetConfig { packageLoader = s2nLoader }+        s2nPackageConfig = PackageConfig+          { enableCheck     = opts ^. optDoCheckStackage+          , enableHaddock   = opts ^. optDoHaddockStackage }+      stackagePackages <- traverse (uncurry (buildNode s2nPackageSetConfig s2nPackageConfig))+        $ Map.toAscList (bpPackages buildPlan) -  -- Find all reachable dependencies in stackage set to stick into-  -- stackage packages file. This is performed on the full stackage-  -- set rather than pruning stackage packages beforehand because-  -- stackage does not concern itself with build tools while cabal2nix-  -- does: pruning only after generating full set of packages allows-  -- us to make sure all those extra dependencies are explicitly-  -- listed as well.-  let nodes = case opts ^. optOutPackagesClosure of-        True -> flip reachableDependencies allNodes-                -- Originally reachable nodes are root nodes-                $ filter (\n -> mkPackageName (nodeName n) `Set.member` reachable) allNodes-        False -> allNodes+      let+        -- Nixpkgs generic-builder puts hscolour on path for all libraries+        withHscolour pkgs =+          let hscolour = F.find ((== "hscolour") . nodeName) stackagePackages+          in maybe pkgs (`Set.insert` pkgs) hscolour+        -- Find all reachable dependencies in stackage set to stick into+        -- stackage packages file. This is performed on the full stackage+        -- set rather than pruning stackage packages beforehand because+        -- stackage does not concern itself with build tools while cabal2nix+        -- does: pruning only after generating full set of packages allows+        -- us to make sure all those extra dependencies are explicitly+        -- listed as well.+        nodes = case opts ^. optOutPackagesClosure of+          True -> Set.toAscList+            $ withHscolour+            $ flip reachableDependencies stackagePackages+            -- Originally reachable nodes are root nodes+            $ L.filter (\n -> mkPackageName (nodeName n) `Set.member` reachable) stackagePackages+          False -> stackagePackages+      writeOutFile buildPlanFile (opts ^. optOutStackagePackages)+        $ pPrintOutPackages (view nodeDerivation <$> nodes)+      writeOutFile buildPlanFile (opts ^. optOutStackageConfig)+        $ pPrintOutConfig (bpSystemInfo buildPlan) nodes+      writeOutFile (stackYaml ^. syFilePath) (opts ^. optOutDerivation)+        $ PP.overrideHaskellPackages overrideConfig stackConfPackages -  withFile (opts ^. optOutStackagePackages) WriteMode $ \h -> do-    hPutStrLn h ("# Generated by stackage2nix " ++ Text.display version ++ " from " ++ buildPlanFile)-    hPutStrLn h $ render $ pPrintOutPackages (view nodeDerivation <$> nodes)-  withFile (opts ^. optOutStackageConfig) WriteMode $ \h -> do-    hPutStrLn h ("# Generated by stackage2nix " ++ Text.display version ++ " from " ++ buildPlanFile)-    hPutStrLn h $ render $ pPrintOutConfig (bpSystemInfo buildPlan) nodes+    -- Generate Stackage packages from resolver+    OriginResolver stackResolver -> do+      let+        buildPlanFile = LH.buildPlanFilePath (opts ^. optLtsHaskellRepo) stackResolver+        packageConfig = PackageConfig+          { enableCheck     = True+          , enableHaddock   = True }+      buildPlan <- LH.loadBuildPlan buildPlanFile+      packageSetConfig <- LH.buildPackageSetConfig+        (opts ^. optHackageDb)+        (opts ^. optAllCabalHashesRepo)+        (opts ^. optNixpkgsRepository)+        buildPlan+      nodes <- traverse (uncurry (buildNode packageSetConfig packageConfig))+        $ Map.toAscList (bpPackages buildPlan)+      let overrideConfig = mkOverrideConfig opts (siGhcVersion $ bpSystemInfo buildPlan)++      writeOutFile buildPlanFile (opts ^. optOutStackagePackages)+        $ pPrintOutPackages (view nodeDerivation <$> nodes)+      writeOutFile buildPlanFile (opts ^. optOutStackageConfig)+        $ pPrintOutConfig (bpSystemInfo buildPlan) nodes+      writeOutFile buildPlanFile (opts ^. optOutDerivation)+        $ PP.pPrintHaskellPackages overrideConfig++writeOutFile :: Show source => source -> FilePath -> Doc -> IO ()+writeOutFile source filePath contents =+  withFile filePath WriteMode $ \h -> do+    hPutStrLn h ("# Generated by stackage2nix " ++ Text.display version ++ " from " ++ show source)+    hPutStrLn h $ render contents  mkOverrideConfig :: Options -> Version -> OverrideConfig mkOverrideConfig opts ghcVersion = OverrideConfig
src/Runner/Cli.hs view
@@ -10,27 +10,37 @@ import qualified Distribution.Text as Text import           Options.Applicative as Opts import           Paths_stackage2nix ( version )+import           Stack.Config import           Stack.Types import           System.Environment import           System.FilePath +-- | Source that would be used to produce target derivation+data ConfigOrigin+  = OriginResolver StackResolver+  -- ^ Resolver to generate Stackage LTS+  | OriginStackYaml StackYaml+  -- ^ Stack config to generate build derivation+  deriving (Show) +makePrisms ''ConfigOrigin+ data Options = Options-  { _optAllCabalHashesRepo  :: !FilePath-  , _optLtsHaskellRepo      :: !FilePath-  , _optOutStackagePackages :: !FilePath-  , _optOutStackageConfig   :: !FilePath-  , _optOutPackagesClosure  :: !Bool-  , _optOutDerivation       :: !FilePath-  , _optDoCheckPackages     :: !Bool-  , _optDoHaddockPackages   :: !Bool-  , _optDoCheckStackage     :: !Bool-  , _optDoHaddockStackage   :: !Bool-  , _optHackageDb           :: !(Maybe HackageDb)-  , _optNixpkgsRepository   :: !FilePath-  , _optCompilerId          :: !CompilerId-  , _optPlatform            :: !Platform-  , _optStackYamlArg        :: !FilePath+  { _optAllCabalHashesRepo  :: FilePath+  , _optLtsHaskellRepo      :: FilePath+  , _optOutStackagePackages :: FilePath+  , _optOutStackageConfig   :: FilePath+  , _optOutPackagesClosure  :: Bool+  , _optOutDerivation       :: FilePath+  , _optDoCheckPackages     :: Bool+  , _optDoHaddockPackages   :: Bool+  , _optDoCheckStackage     :: Bool+  , _optDoHaddockStackage   :: Bool+  , _optHackageDb           :: (Maybe HackageDb)+  , _optNixpkgsRepository   :: FilePath+  , _optCompilerId          :: CompilerId+  , _optPlatform            :: Platform+  , _optConfigOrigin        :: ConfigOrigin   } deriving (Show)  makeLenses ''Options@@ -38,9 +48,6 @@ envStackYaml :: IO (Maybe StackYaml) envStackYaml = fmap mkStackYaml <$> lookupEnv "STACK_YAML" -optStackYaml :: Getter Options StackYaml-optStackYaml = optStackYamlArg . to mkStackYaml- mkStackYaml :: FilePath -> StackYaml mkStackYaml p = case splitFileName p of   (dir, "")   -> StackYaml dir "stack.yaml"@@ -64,7 +71,7 @@   <*> nixpkgsRepository   <*> compilerId   <*> platform-  <*> stackYamlArg+  <*> configOrigin  pinfo :: ParserInfo Options pinfo = info@@ -143,10 +150,19 @@   ( long "do-haddock-stackage"     <> help "enable haddock for Stackage packages" ) -stackYamlArg :: Parser FilePath-stackYamlArg = Opts.argument str+resolver :: Parser StackResolver+resolver = StackResolver <$> option text+  ( long "resolver"+    <> help "stackage LTS resolver" )++stackYamlArg :: Parser StackYaml+stackYamlArg = mkStackYaml <$> Opts.argument str   ( metavar "STACK_YAML"     <> help "path to stack.yaml file or directory" )++configOrigin :: Parser ConfigOrigin+configOrigin = OriginResolver <$> resolver+  <|> OriginStackYaml <$> stackYamlArg  -- inherited from cabal2nix 
src/Stack/Config.hs view
@@ -9,6 +9,7 @@ import Data.Foldable as F import Data.List.NonEmpty as NE import Data.Maybe+import Data.Semigroup (sconcat) import Data.Text as T import Data.Yaml import Network.URI@@ -48,6 +49,8 @@ data StackPackage = StackPackage   { _spLocation :: !PackageLocation   , _spExtraDep :: !Bool+    -- | Subdirectory containing the cabal file if any specified.+  , _spDir  :: !(Maybe FilePath)   } deriving (Eq, Ord, Show)  makeLenses ''StackPackage@@ -62,28 +65,39 @@ fromYamlConfig :: Yaml.Config -> StackConfig fromYamlConfig c = StackConfig{..}   where-    _scResolver    = coerce $ c ^. cResolver-    _scPackages    = F.foldr (NE.<|) neYamlPackages yamlExtraDeps-    neYamlPackages = fromMaybe (pure defaultPackage) $ NE.nonEmpty yamlPackages-    yamlPackages   = fromYamlPackage <$> fromMaybe mempty (c ^. cPackages)+    _scResolver = coerce $ c ^. cResolver+    _scPackages = F.foldr (NE.<|) neYamlPackages yamlExtraDeps+    neYamlPackages = fromMaybe (pure defaultPackage)+                   . fmap sconcat $ NE.nonEmpty yamlPackages+    yamlPackages   = fromYamlPackage <$> (fromMaybe mempty (c ^. cPackages))     yamlExtraDeps  = fromYamlExtraDep <$> fromMaybe mempty (c ^. cExtraDeps)-    defaultPackage = StackPackage (StackFilePath ".") False+    defaultPackage = StackPackage (StackFilePath ".") False Nothing -fromYamlPackage :: Yaml.Package -> StackPackage++fromYamlPackage+  :: Yaml.Package+     -- ^ A single 'Yaml.Package' can result in multiple actual+     -- packages if it has multiple subdirs specified.+  -> NonEmpty StackPackage fromYamlPackage = \case   Yaml.Simple p                                  ->-    StackPackage (parseSimplePath p) False-  Yaml.LocationSimple (Yaml.Location p extraDep) ->-    StackPackage (parseSimplePath p) (fromMaybe False extraDep)-  Yaml.LocationGit (Location git extraDep)       ->-    StackPackage (StackRepo $ fromYamlGit git) (fromMaybe False extraDep)-  Yaml.LocationHg (Location hg extraDep)       ->-    StackPackage (StackRepo $ fromYamlHg hg) (fromMaybe False extraDep)+    unroll Nothing $ StackPackage (parseSimplePath p) False+  Yaml.LocationSimple (Location p extraDep ms) ->+    unroll ms $ StackPackage (parseSimplePath p) (fromMaybe False extraDep)+  Yaml.LocationGit (Location git extraDep ms)       ->+    unroll ms $ StackPackage (StackRepo $ fromYamlGit git) (fromMaybe False extraDep)+  Yaml.LocationHg (Location hg extraDep ms)       ->+    unroll ms $ StackPackage (StackRepo $ fromYamlHg hg) (fromMaybe False extraDep)   where     parseSimplePath (T.unpack -> p) = maybe (StackFilePath p) StackUri $ parseURI p+    -- Each package gets a single directory with cabal file in it. If+    -- it's not specified, path is empty.+    unroll subs p = case subs of+      Just (x : xs) -> NE.map (p . Just) (x :| xs)+      _ -> p Nothing :| []  fromYamlExtraDep :: Text -> StackPackage-fromYamlExtraDep = flip StackPackage True . HackagePackage+fromYamlExtraDep t = StackPackage (HackagePackage t) True Nothing  fromYamlGit :: Yaml.Git -> Repo fromYamlGit yg = Repo{..}
src/Stack/Config/Yaml.hs view
@@ -10,6 +10,7 @@ data Location a = Location   { _lLocation :: !a   , _lExtraDep :: !(Maybe Bool)+  , _lSubdirs :: !(Maybe [FilePath])   } deriving (Eq, Show)  makeLenses ''Location
src/Stack/Types.hs view
@@ -10,6 +10,7 @@ data StackYaml = StackYaml   { _syDirName  :: !FilePath   , _syFileName :: !FilePath }+  deriving (Ord, Eq, Show)  makeLenses ''StackYaml 
stackage2nix.cabal view
@@ -1,7 +1,7 @@ name:                stackage2nix-version:             0.3.0+version:             0.4.0 synopsis:            Convert Stack files into Nix build instructions.-homepage:            https://github.com/4e6/stackage2nix#readme+homepage:            https://github.com/typeable/stackage2nix#readme license:             BSD3 license-file:        LICENSE author:              Dmitry Bushev@@ -44,7 +44,7 @@                      , gitlib > 3                      , gitlib-libgit2 > 3                      , hopenssl > 2.2-                     , inflections+                     , inflections >= 0.3                      , language-nix                      , lens                      , network-uri@@ -91,4 +91,4 @@  source-repository head   type:     git-  location: https://github.com/4e6/stackage2nix+  location: https://github.com/typeable/stackage2nix
test/Stack/Config/YamlSpec.hs view
@@ -28,6 +28,12 @@   - location:       git: git@github.com:commercialhaskell/stack.git       commit: 6a86ee32e5b869a877151f74064572225e1a0398+  - location:+      git: git@github.com:example/mega-repo+      commit: 6a86ee32e5b869a877151f74064572225e1a0000+    subdirs:+      - subdir1+      - subdir2 # Comment extra-deps: - acme-missiles-0.3@@ -45,13 +51,19 @@   { _cResolver = "lts-3.7"   , _cPackages = Just     [ Simple "."-    , LocationSimple (Location "dir1/dir2" Nothing)-    , LocationSimple (Location "https://example.com/foo/bar/baz-0.0.2.tar.gz" (Just True))+    , LocationSimple (Location "dir1/dir2" Nothing Nothing)+    , LocationSimple (Location "https://example.com/foo/bar/baz-0.0.2.tar.gz" (Just True) Nothing)     , LocationGit $ Location        (Git         "git@github.com:commercialhaskell/stack.git"         "6a86ee32e5b869a877151f74064572225e1a0398")-       Nothing]+       Nothing Nothing+    , LocationGit (Location+       (Git+        "git@github.com:example/mega-repo"+        "6a86ee32e5b869a877151f74064572225e1a0000")+       Nothing (Just ["subdir1", "subdir2"]))+    ]   , _cExtraDeps = Just     ["acme-missiles-0.3"]   }