cabal2nix 1.73 → 2.0
raw patch · 41 files changed
+2468/−2102 lines, 41 filesdep +SHAdep +aesondep +ansi-wl-pprintdep −doctestdep −regex-posixdep ~Cabaldep ~basedep ~deepseqsetup-changednew-component:exe:hackage2nix
Dependencies added: SHA, aeson, ansi-wl-pprint, bytestring, cabal2nix, distribution-nixpkgs, language-nix, lens, monad-par, monad-par-extras, optparse-applicative, split, stackage-types, text, time, utf8-string, yaml
Dependencies removed: doctest, regex-posix
Dependency ranges changed: Cabal, base, deepseq, hackage-db, pretty
Files
- README.md +0/−182
- Setup.hs +0/−15
- Setup.lhs +40/−0
- cabal2nix.cabal +178/−103
- cabal2nix/Main.hs +161/−0
- hackage2nix/HackageGit.hs +79/−0
- hackage2nix/Main.hs +259/−0
- hackage2nix/Stackage.hs +114/−0
- src/Cabal2Nix/CorePackages.hs +0/−43
- src/Cabal2Nix/Flags.hs +0/−31
- src/Cabal2Nix/Generate.hs +0/−66
- src/Cabal2Nix/License.hs +0/−27
- src/Cabal2Nix/Name.hs +0/−131
- src/Cabal2Nix/Normalize.hs +0/−70
- src/Cabal2Nix/Package.hs +0/−145
- src/Cabal2Nix/PostProcess.hs +0/−322
- src/Cabal2Nix/Version.hs +0/−7
- src/Distribution/NixOS/Derivation/Cabal.hs +0/−195
- src/Distribution/NixOS/Derivation/License.hs +0/−56
- src/Distribution/NixOS/Derivation/Meta.hs +0/−80
- src/Distribution/NixOS/Fetch.hs +0/−142
- src/Distribution/NixOS/PrettyPrinting.hs +0/−56
- src/Distribution/NixOS/Regex.hs +0/−25
- src/Distribution/Nixpkgs/Fetch.hs +155/−0
- src/Distribution/Nixpkgs/Haskell.hs +8/−0
- src/Distribution/Nixpkgs/Haskell/BuildInfo.hs +45/−0
- src/Distribution/Nixpkgs/Haskell/Constraint.hs +15/−0
- src/Distribution/Nixpkgs/Haskell/Derivation.hs +148/−0
- src/Distribution/Nixpkgs/Haskell/FromCabal.hs +138/−0
- src/Distribution/Nixpkgs/Haskell/FromCabal/Configuration.hs +101/−0
- src/Distribution/Nixpkgs/Haskell/FromCabal/Flags.hs +57/−0
- src/Distribution/Nixpkgs/Haskell/FromCabal/License.hs +30/−0
- src/Distribution/Nixpkgs/Haskell/FromCabal/Name.hs +198/−0
- src/Distribution/Nixpkgs/Haskell/FromCabal/Normalize.hs +57/−0
- src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs +383/−0
- src/Distribution/Nixpkgs/Haskell/Hackage.hs +29/−0
- src/Distribution/Nixpkgs/Haskell/OrphanInstances.hs +116/−0
- src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs +157/−0
- src/cabal2nix.hs +0/−109
- src/hackage4nix.hs +0/−260
- test/doc-test.hs +0/−37
− README.md
@@ -1,182 +0,0 @@-How to maintain Haskell Packages in Nix-=======================================--## Overview over the tool-chain--There are two utilities, `cabal2nix` and `hackage4nix`, that automate-maintenance to a large extent. We intend to merge them into one program,-eventually, but the necessary re-factoring hasn't been done yet since-this is not a high priority.--### Cabal2nix--`cabal2nix` converts a single Cabal file into a single Nix build-expression. For example:-- $ cabal2nix cabal://yesod-0.9.1- { cabal, attoparsecText, blazeBuilder, blazeHtml, hamlet, httpTypes- , monadControl, parsec, shakespeareCss, shakespeareJs, text, time- , transformers, unixCompat, wai, waiExtra, warp, yesodAuth- , yesodCore, yesodForm, yesodJson, yesodPersistent- }:-- cabal.mkDerivation (self: {- pname = "yesod";- version = "0.9.1";- sha256 = "1ag3lca75lrriycbscspb5yyishacgxjx0rybc3x4z1dqnkn1r71";- isLibrary = true;- isExecutable = true;- buildDepends = [- attoparsecText blazeBuilder blazeHtml hamlet httpTypes monadControl- parsec shakespeareCss shakespeareJs text time transformers- unixCompat wai waiExtra warp yesodAuth yesodCore yesodForm- yesodJson yesodPersistent- ];- meta = {- homepage = "http://www.yesodweb.com/";- description = "Creation of type-safe, RESTful web applications";- license = self.stdenv.lib.licenses.bsd3;- platforms = self.ghc.meta.platforms;- };- })--Cabal files can be referred to using the magic URL-`cabal://NAME-VERSION`, which will automatically download the file from-Hackage. Alternatively, a direct `http://host/path/pkg.cabal` URL can be-provided, as well as a `file:///local/path/pkg.cabal` URI that doesn't-depend on network access. However, if the source hash is not already in `cabal2nix`'s cache or-provided using the `--sha256` option, `cabal2nix` still needs to download the source code to-compute the hash, which obviously still causes network traffic.-Run the utility with `--help` to see the complete list of supported command line flags.--To add a new package to Nix, checkout the Nixpkgs project from-https://github.com/nixos/nixpkgs.git and run-- $ cd pkgs/development/libraries/haskell- $ mkdir foo- $ cabal2nix cabal://foo-1.0 >foo/default.nix--Then add an appropriate attribute to-`pkgs/top-level/haskell-packages.nix`, for example:-- foo = callPackage ../development/libraries/haskell/foo {};--`cabal2nix` can also build derivations for projects from other-sources than hackage. You only need to provide an URI that points-to a cabal project. The most common usecase for this is probably to-generate a derivation for a project on the local file system:-- aeson:$ cabal2nix ./.- # This file was auto-generated by cabal2nix. Please do NOT edit manually!-- { cabal, attoparsec, blazeBuilder, deepseq, dlist, hashable, HUnit- , mtl, QuickCheck, scientific, syb, testFramework- , testFrameworkHunit, testFrameworkQuickcheck2, text, time- , unorderedContainers, vector- }-- cabal.mkDerivation (self: {- pname = "aeson";- version = "0.7.0.2";- src = ./.;- buildDepends = [- attoparsec blazeBuilder deepseq dlist hashable mtl scientific syb- text time unorderedContainers vector- ];- testDepends = [- attoparsec HUnit QuickCheck testFramework testFrameworkHunit- testFrameworkQuickcheck2 text time unorderedContainers vector- ];- meta = {- homepage = "https://github.com/bos/aeson";- description = "Fast JSON parsing and encoding";- license = self.stdenv.lib.licenses.bsd3;- platforms = self.ghc.meta.platforms;- };- })--This derivation will not fetch from hackage, but instead use the directory which-contains the derivation as the source repository.--`cabal2nix` currently supports the following respository types:--* directory-* source archive (zip, tar.gz, ...) from http or https URL or local file.-* git, mercurial, svn or bazaar repository--### Hackage4nix--The `hackage4nix` utility re-generates *all* expressions found in the-`nixpkgs` database in place. This is useful to ensure that all packages-have been generated with a recent version of the tool-chain.-Furthermore, `hackage4nix` adds default settings for the-`meta.maintainers` and `meta.platforms` attribute if these aren't-configured yet. Generally speaking, running-- $ hackage4nix pkgs--in your checked-out copy of the Nixpkgs tree should be a *no-op* ----i.e. no files should change! If there are changes, these indicate that a-file has been modified manually, and then these changes must be-investigated to find out what is going on.--Last but not least, `hackage4nix` generates a list of all updates-available from Hackage. (Run `cabal update` to make sure that your local-copy of the Hackage database is up-to-date!) For example:-- $ hackage4nix pkgs- The following updates are available:-- WebBits-Html-1.0.1:- cabal2nix cabal://WebBits-Html-1.0.2 >pkgs/pkgs/development/libraries/haskell/WebBits-Html/default.nix-- happstack-server-6.1.6:- cabal2nix cabal://happstack-server-6.2.1 >pkgs/pkgs/development/libraries/haskell/happstack/happstack-server.nix- cabal2nix cabal://happstack-server-6.2.2 >pkgs/pkgs/development/libraries/haskell/happstack/happstack-server.nix-- primitive-0.3.1:- cabal2nix cabal://primitive-0.4 >pkgs/pkgs/development/libraries/haskell/primitive/default.nix-- repa-2.1.1.5:- cabal2nix cabal://repa-2.1.1.6 >pkgs/pkgs/development/libraries/haskell/repa/default.nix-- unix-compat-0.2.2.1:- cabal2nix cabal://unix-compat-0.3 >pkgs/pkgs/development/libraries/haskell/unix-compat/default.nix-- vector-0.7.1:- cabal2nix cabal://vector-0.8 >pkgs/pkgs/development/libraries/haskell/vector/default.nix--These updates can be performed automatically by running the `cabal2nix`-command given by `hackage4nix`. If there is more than one possible-update, then all of them will be shown. Note, however, that some updates-break compilation of other packages, because they depend on very-specific versions of their build inputs, so please be careful when-performing updates!--## Current State of Affairs--The tool-chain is stable. As of today, 2013-04-12, virtually all Haskell-packages available in Nix have been generated automatically from their-Cabal files. There are only a handful of exceptions, which we cannot-generate because these packages aren't available on Hackage. The list of-those packages is hard-coded into the-[`hackage4nix.hs`](https://github.com/NixOS/cabal2nix/blob/master/src/hackage4nix.hs)-binary in the function `badPackagePaths`.--Furthermore, Hackage4Nix will not re-generate packages that have been-patched, i.e. that define any of the following attributes:-- (pre|post)Configure- (pre|post)Install- patchPhase- patches--These packages are considered for updates, however.--The complete list of Haskell packages available in Nix is generated by-the tool [`package-list`](http://github.com/peti/package-list),-and published at <http://cryp.to/haskell-in-nixpkgs.txt>. Hackage picks-it up from there and generates links on each package's homepage to the-corresponding page in Hydra automatically. See [ticket-875](http://www.haskell.org/pipermail/cabal-devel/2011-August/007714.html) for further-details.
− Setup.hs
@@ -1,15 +0,0 @@-module Main ( main ) where--import Distribution.Simple-import Distribution.Simple.LocalBuildInfo ( withPrograms )-import Distribution.Simple.Program ( userSpecifyArgs )--main :: IO ()-main = defaultMainWithHooks $- simpleUserHooks `modify_haddockHook` \oldHH pkg lbi hooks flags ->- (\lbi' -> oldHH pkg lbi' hooks flags) $- lbi `modify_withPrograms` \oldWP ->- userSpecifyArgs "haddock" ["--optghc=-D__HADDOCK__"] oldWP- where- modify_haddockHook hooks f = hooks { haddockHook = f (haddockHook hooks) }- modify_withPrograms lbi f = lbi { withPrograms = f (withPrograms lbi) }
+ Setup.lhs view
@@ -0,0 +1,40 @@+#! /usr/bin/env runhaskell++> module Main ( main ) where+>+> import Data.Char+> import Data.Maybe+> import Distribution.PackageDescription+> import Distribution.Simple+> import Distribution.Simple.LocalBuildInfo+> import Distribution.Simple.Program+> import Distribution.Simple.Setup+>+> main :: IO ()+> main = defaultMainWithHooks simpleUserHooks+> { hookedPrograms = map simpleProgram programs+> , confHook = configure+> }+>+> programs :: [String]+> programs = ["nix-instantiate", "nix-build", "nix-env", "nix-store"]+>+> configure :: (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags -> IO LocalBuildInfo+> configure (gpd, hbi) flags = do+> lbi' <- confHook simpleUserHooks (gpd, hbi) flags+> let paths = map (\p -> (p, maybe p programPath (lookupProgram (simpleProgram p) (withPrograms lbi)))) programs+> descr = localPkgDescr lbi'+> lib = fromJust (library descr)+> libbi = libBuildInfo lib+> lbi = lbi' { localPkgDescr = descr+> { library = Just (lib { libBuildInfo = libbi { cppOptions = cppOptions libbi ++ map fmtCppArg paths } })+> }+> }+> return lbi+>+> fmtCppArg :: (String, FilePath) -> String+> fmtCppArg (prg, path) = "-DPATH_TO_" ++ map mangle prg ++ "=" ++ show path+> where+> mangle :: Char -> Char+> mangle '-' = '_'+> mangle c = toUpper c
cabal2nix.cabal view
@@ -1,107 +1,182 @@-Name: cabal2nix-Version: 1.73-Copyright: Peter Simons, Andres Loeh-License: BSD3-License-File: LICENSE-Author: Peter Simons <simons@cryp.to>, Andres Loeh <mail@andres-loeh.de>-Maintainer: Nix Developers <nix-dev@lists.science.uu.nl>-Homepage: http://github.com/NixOS/cabal2nix-Category: Distribution-Synopsis: Convert Cabal files into Nix build instructions-Cabal-Version: >= 1.8-Build-Type: Custom-Tested-With: GHC >= 7.0.4 && <= 7.8.3-Data-files: README.md-Description:- The @cabal2nix@ utility converts Cabal files into Nix build instructions. The- commandline syntax is:- .- > Usage: cabal2nix [options] url-to-cabal-file-or-repo- > -h --help show this help text- > -v --version print version- > --hackage-db=FILEPATH path to the local hackage db in tar format- > --sha256=HASH sha256 hash of source tarball- > -m MAINTAINER --maintainer=MAINTAINER maintainer of this package (may be specified multiple times)- > -p PLATFORM --platform=PLATFORM supported build platforms (may be specified multiple times)- > --jailbreak don't honor version restrictions on build inputs- > --no-haddock don't run Haddock when building this package- > --no-check don't run regression test suites of this package- > --no-hyperlink-source don't add pretty-printed source code to the documentation- >- > Recognized URI schemes:- >- > cabal://pkgname-pkgversion download the specified package from Hackage- > cabal://pkgname download latest version of the specified package from Hackage- > http://host/path fetch the Cabal file via HTTP- > file:///local/path load the Cabal file from the local disk- > /local/path.cabal abbreviated version of file URI- > <git/svn/bzr/hg URL> download the source from the specified repository- .- The only required argument is the path to the cabal file. For example:- .- > cabal2nix http://hackage.haskell.org/packages/archive/cabal2nix/1.73/cabal2nix.cabal- > cabal2nix cabal://cabal2nix-1.73- .- If the @--sha256@ option has not been specified, cabal2nix calls- @nix-prefetch-url@ to determine the hash automatically. This causes- network traffic, obviously.- .- If the argument refers to a source repository instead of a cabal file,- cabal2nix will use that source repository to fetch from instead of hackage.- Currently, cabal2nix supports directories, archives (fetched via http or https) and- git, mercurial, svn or bazaar repositories.+-- This file has been generated from package.yaml by hpack version 0.14.1.+--+-- see: https://github.com/sol/hpack -Source-Repository head- Type: git- Location: git://github.com/NixOS/cabal2nix.git+name: cabal2nix+version: 2.0+synopsis: Convert Cabal files into Nix build instructions.+description: Convert Cabal files into Nix build instructions. Users of Nix can install the latest version by running:+ > nix-env -i cabal2nix+category: Distribution, Nix+homepage: https://github.com/nixos/cabal2nix#readme+bug-reports: https://github.com/nixos/cabal2nix/issues+author: Peter Simons,+ Andres Loeh,+ Benno Fünfstück,+ Mateusz Kowalczyk,+ Mathijs Kwik,+ Michael Alan Dorman,+ Shea Levy,+ Dmitry Malikov,+ Eric Seidel,+ Nikolay Amiantov,+ Aycan iRiCAN,+ John Wiegley,+ Philipp Hausmann,+ Spencer Janssen,+ William Casarin,+ Adam Vogt,+ Bryan Gardiner,+ Corey O'Connor,+ Cray Elliott,+ Felix Kunzmann,+ Gabriel Ebner,+ Gergely Risko,+ John Albietz,+ John Chee,+ Jussi Maki,+ Mark Laws,+ Mark Wotton,+ Matvey Aksenov,+ Nicolas Rolland,+ Oliver Charles,+ Pascal Wittmann,+ Patrick John Wheeler,+ Raymond Gauthier,+ Renzo Carbonara,+ Sibi,+ Tanner Doshier,+ Tom Hunger,+ Viktar Basharymau,+ danbst,+ karsten gebbert,+ laMudri,+ Александр Цамутали+maintainer: Peter Simons <simons@cryp.to>+license: BSD3+license-file: LICENSE+tested-with: GHC > 7.10 && < 8.1+build-type: Simple+cabal-version: >= 1.10 -Executable cabal2nix- main-is: cabal2nix.hs- hs-source-dirs: src- Build-Depends: base >= 3 && < 5, regex-posix, pretty, Cabal >= 1.18,- filepath, directory, process, hackage-db >= 1.11, transformers, deepseq- Extensions: PatternGuards, RecordWildCards, CPP- Ghc-Options: -Wall- other-modules: Cabal2Nix.CorePackages- Cabal2Nix.Flags- Cabal2Nix.Generate- Cabal2Nix.Package- Cabal2Nix.License- Cabal2Nix.Name- Cabal2Nix.Normalize- Cabal2Nix.PostProcess- Cabal2Nix.Version- Distribution.NixOS.Fetch- Distribution.NixOS.Derivation.Cabal- Distribution.NixOS.Derivation.License- Distribution.NixOS.Derivation.Meta- Distribution.NixOS.PrettyPrinting- Distribution.NixOS.Regex+source-repository head+ type: git+ location: https://github.com/nixos/cabal2nix -Executable hackage4nix- main-is: hackage4nix.hs- hs-source-dirs: src- Build-Depends: base >= 3 && < 5, regex-posix, pretty, Cabal >= 1.18,- mtl, containers, directory, filepath, hackage-db >= 1.11,- transformers, process, deepseq- Extensions: PatternGuards, RecordWildCards, CPP- Ghc-Options: -Wall- other-modules: Cabal2Nix.CorePackages- Cabal2Nix.Flags- Cabal2Nix.Generate- Cabal2Nix.License- Cabal2Nix.Name- Cabal2Nix.Normalize- Cabal2Nix.PostProcess- Distribution.NixOS.Fetch- Distribution.NixOS.Derivation.Cabal- Distribution.NixOS.Derivation.License- Distribution.NixOS.Derivation.Meta- Distribution.NixOS.PrettyPrinting- Distribution.NixOS.Regex+library+ hs-source-dirs:+ src+ ghc-options: -Wall+ build-depends:+ aeson+ , ansi-wl-pprint+ , base < 5+ , bytestring+ , Cabal > 1.24+ , containers+ , deepseq >= 1.4+ , directory+ , distribution-nixpkgs+ , filepath+ , hackage-db+ , language-nix+ , lens+ , optparse-applicative+ , pretty >= 1.1.2+ , process+ , SHA+ , split+ , text+ , transformers+ , yaml+ exposed-modules:+ Distribution.Nixpkgs.Fetch+ Distribution.Nixpkgs.Haskell+ Distribution.Nixpkgs.Haskell.BuildInfo+ Distribution.Nixpkgs.Haskell.Constraint+ Distribution.Nixpkgs.Haskell.Derivation+ Distribution.Nixpkgs.Haskell.FromCabal+ Distribution.Nixpkgs.Haskell.FromCabal.Configuration+ Distribution.Nixpkgs.Haskell.FromCabal.Flags+ Distribution.Nixpkgs.Haskell.FromCabal.License+ Distribution.Nixpkgs.Haskell.FromCabal.Name+ Distribution.Nixpkgs.Haskell.FromCabal.Normalize+ Distribution.Nixpkgs.Haskell.FromCabal.PostProcess+ Distribution.Nixpkgs.Haskell.Hackage+ Distribution.Nixpkgs.Haskell.OrphanInstances+ Distribution.Nixpkgs.Haskell.PackageSourceSpec+ other-modules:+ Paths_cabal2nix+ default-language: Haskell2010 -Test-Suite doctest-cabal2nix- type: exitcode-stdio-1.0- main-is: doc-test.hs- hs-source-dirs: test- build-depends: base, doctest+executable cabal2nix+ main-is: Main.hs+ hs-source-dirs:+ cabal2nix+ ghc-options: -Wall+ build-depends:+ aeson+ , ansi-wl-pprint+ , base < 5+ , bytestring+ , Cabal > 1.24+ , containers+ , deepseq >= 1.4+ , directory+ , distribution-nixpkgs+ , filepath+ , hackage-db+ , language-nix+ , lens+ , optparse-applicative+ , pretty >= 1.1.2+ , process+ , SHA+ , split+ , text+ , transformers+ , yaml+ , cabal2nix+ other-modules:+ Paths_cabal2nix+ default-language: Haskell2010++executable hackage2nix+ main-is: Main.hs+ hs-source-dirs:+ hackage2nix+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ aeson+ , ansi-wl-pprint+ , base < 5+ , bytestring+ , Cabal > 1.24+ , containers+ , deepseq >= 1.4+ , directory+ , distribution-nixpkgs+ , filepath+ , hackage-db+ , language-nix+ , lens+ , optparse-applicative+ , pretty >= 1.1.2+ , process+ , SHA+ , split+ , text+ , transformers+ , yaml+ , cabal2nix+ , monad-par+ , monad-par-extras+ , mtl+ , stackage-types+ , time+ , utf8-string+ other-modules:+ Paths_cabal2nix+ HackageGit+ Stackage+ default-language: Haskell2010
+ cabal2nix/Main.hs view
@@ -0,0 +1,161 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}++module Main ( main ) where++import Control.Exception ( bracket )+import Control.Lens+import Data.Maybe ( fromMaybe )+import qualified Data.Set as Set+import qualified Distribution.Compat.ReadP as P+import Distribution.Compiler+import Distribution.Nixpkgs.Fetch+import Distribution.Nixpkgs.Haskell+import Distribution.Nixpkgs.Haskell.FromCabal+import Distribution.Nixpkgs.Haskell.PackageSourceSpec+import Distribution.Nixpkgs.Meta+import Distribution.PackageDescription ( FlagName(..), FlagAssignment )+import Distribution.Simple.Utils ( lowercase )+import Distribution.System+import Distribution.Text+import Language.Nix+import Options.Applicative+import Paths_cabal2nix ( version )+import System.IO ( hFlush, stdout, stderr )+import qualified Text.PrettyPrint.ANSI.Leijen as P2 hiding ( (<$>), (<>) )+import Text.PrettyPrint.HughesPJClass ( Doc, Pretty(..), text, vcat, hcat, semi )++data Options = Options+ { optSha256 :: Maybe String+ , optMaintainer :: [String]+--, optPlatform :: [String] -- TODO: fix command line handling of platforms+ , optHaddock :: Bool+ , optDoCheck :: Bool+ , optJailbreak :: Bool+ , optRevision :: Maybe String+ , optHyperlinkSource :: Bool+ , optEnableLibraryProfiling :: Bool+ , optEnableExecutableProfiling :: Bool+ , optEnableProfiling :: Maybe Bool+ , optExtraArgs :: [String]+ , optHackageDb :: Maybe FilePath+ , optNixShellOutput :: Bool+ , optFlags :: [String]+ , optCompiler :: CompilerId+ , optSystem :: Platform+ , optUrl :: String+ }+ deriving (Show)++options :: Parser Options+options = Options+ <$> optional (strOption $ long "sha256" <> metavar "HASH" <> help "sha256 hash of source tarball")+ <*> many (strOption $ long "maintainer" <> metavar "MAINTAINER" <> help "maintainer of this package (may be specified multiple times)")+-- <*> many (strOption $ long "platform" <> metavar "PLATFORM" <> help "supported build platforms (may be specified multiple times)")+ <*> flag True False (long "no-haddock" <> help "don't run Haddock when building this package")+ <*> flag True False (long "no-check" <> help "don't run regression test suites of this package")+ <*> switch (long "jailbreak" <> help "disregard version restrictions on build inputs")+ <*> optional (strOption $ long "revision" <> help "revision to use when fetching from VCS")+ <*> flag True False (long "no-hyperlink-source" <> help "don't generate pretty-printed source code for the documentation")+ <*> switch (long "enable-library-profiling" <> help "enable library profiling in the generated build")+ <*> switch (long "enable-executable-profiling" <> help "enable executable profiling in the generated build")+ <*> optional (switch (long "enable-profiling" <> help "enable both library and executable profiling in the generated build"))+ <*> many (strOption $ long "extra-arguments" <> help "extra parameters required for the function body")+ <*> optional (strOption $ long "hackage-db" <> metavar "PATH" <> help "path to the local hackage db in tar format")+ <*> switch (long "shell" <> help "generate output suitable for nix-shell")+ <*> many (strOption $ short 'f' <> long "flag" <> help "Cabal flag (may be specified multiple times)")+ <*> option (readP parse) (long "compiler" <> help "compiler to use when evaluating the Cabal file" <> value buildCompilerId <> showDefaultWith display)+ <*> option (readP parsePlatform) (long "system" <> help "target system to use when evaluating the Cabal file" <> value buildPlatform <> showDefaultWith display)+ <*> strArgument (metavar "URI")++readP :: P.ReadP a a -> ReadM a+readP p = eitherReader $ \s -> case [ r' | (r',"") <- P.readP_to_S p s ] of+ (r:_) -> Right r+ _ -> Left ("invalid value " ++ show s)++parsePlatform :: P.ReadP r Platform+parsePlatform = do arch <- P.choice [P.string "i686" >> return I386, P.string "x86_64" >> return X86_64]+ _ <- P.char '-'+ os <- P.choice [P.string "linux" >> return Linux, P.string "darwin" >> return OSX]+ return (Platform arch os)++pinfo :: ParserInfo Options+pinfo = info+ ( helper+ <*> infoOption ("cabal2nix " ++ display version) (long "version" <> help "Show version number")+ <*> options+ )+ ( fullDesc+ <> header "cabal2nix converts Cabal files into build instructions for Nix."+ <> progDescDoc (Just (P2.vcat+ [ P2.text ""+ , P2.text "Recognized URI schemes:"+ , P2.text ""+ , P2.text " cabal://pkgname-pkgversion download the specified package from Hackage"+ , P2.text " cabal://pkgname download latest version of this package from Hackage"+ , P2.text " file:///local/path load the Cabal file from the local disk"+ , P2.text " /local/path abbreviated version of file URI"+ , P2.text " <git/svn/bzr/hg URL> download the source from the specified repository"+ , P2.text ""+ , P2.fillSep (map P2.text (words ( "If the URI refers to a cabal file, information for building the package "+ ++ "will be retrieved from that file, but hackage will be used as a source "+ ++ "for the derivation. Otherwise, the supplied URI will be used to as the "+ ++ "souce for the derivation and the information is taken from the cabal file "+ ++ "at the root of the downloaded source."+ )))+ ]))+ )++main :: IO ()+main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() -> do+ Options {..} <- execParser pinfo++ pkg <- getPackage optHackageDb $ Source optUrl (fromMaybe "" optRevision) (maybe UnknownHash Guess optSha256)++ let+ deriv :: Derivation+ deriv = fromGenericPackageDescription (const True)+ (\i -> Just (binding # (i, path # [i])))+ optSystem+ (unknownCompilerInfo optCompiler NoAbiTag)+ (readFlagList optFlags)+ []+ (pkgCabal pkg)+ & src .~ pkgSource pkg+ & runHaddock .~ optHaddock+ & jailbreak .~ optJailbreak+ & hyperlinkSource .~ optHyperlinkSource+ & enableLibraryProfiling .~ (fromMaybe False optEnableProfiling || optEnableLibraryProfiling)+ & enableExecutableProfiling .~ (fromMaybe False optEnableProfiling || optEnableExecutableProfiling)+ & metaSection.maintainers .~ Set.fromList (map (review ident) optMaintainer)+-- & metaSection.platforms .~ Set.fromList optPlatform+ & doCheck &&~ optDoCheck+ & extraFunctionArgs %~ Set.union (Set.fromList ("stdenv":map (review ident) optExtraArgs))++ shell :: Doc+ shell = vcat+ [ text "{ nixpkgs ? import <nixpkgs> {}, compiler ? \"default\" }:"+ , text ""+ , text "let"+ , text ""+ , text " inherit (nixpkgs) pkgs;"+ , text ""+ , hcat [ text " f = ", pPrint deriv, semi ]+ , text ""+ , text " haskellPackages = if compiler == \"default\""+ , text " then pkgs.haskellPackages"+ , text " else pkgs.haskell.packages.${compiler};"+ , text ""+ , text " drv = haskellPackages.callPackage f {};"+ , text ""+ , text "in"+ , text ""+ , text " if pkgs.lib.inNixShell then drv.env else drv"+ ]++ print (if optNixShellOutput then shell else pPrint deriv)++readFlagList :: [String] -> FlagAssignment+readFlagList = map tagWithValue+ where tagWithValue ('-':fname) = (FlagName (lowercase fname), False)+ tagWithValue fname = (FlagName (lowercase fname), True)
+ hackage2nix/HackageGit.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++module HackageGit where++import Control.Monad+import Control.Lens hiding ( (<.>) )+import Data.Aeson+import Data.ByteString.Char8 ( ByteString )+import qualified Data.ByteString.Char8 as BS+import Data.ByteString.Lazy.Char8 ( fromStrict )+import Data.Digest.Pure.SHA ( sha256, showDigest )+import Data.Map as Map+import Data.Set as Set+import Data.String+import Data.String.UTF8 ( toString, fromRep )+import Distribution.Nixpkgs.Haskell.OrphanInstances ( )+import Distribution.Package+import Distribution.PackageDescription+import Distribution.PackageDescription.Parse ( parsePackageDescription, ParseResult(..) )+import Distribution.Text+import Distribution.Version+import System.Directory+import System.FilePath++type Hackage = Map PackageName (Set Version)++readHackage :: FilePath -> IO Hackage+readHackage path = getSubDirs path >>= foldM discoverPackageVersions mempty+ where+ discoverPackageVersions :: Hackage -> String -> IO Hackage+ discoverPackageVersions db pkg = do+ vs <- getSubDirs (path </> pkg)+ return (Map.insert (PackageName pkg) (Set.fromList (Prelude.map fromString vs)) db)++getSubDirs :: FilePath -> IO [FilePath]+getSubDirs path = do+ let isDirectory p = doesDirectoryExist (path </> p)+ getDirectoryContents path >>= filterM isDirectory . Prelude.filter (\x -> head x /= '.')++decodeUTF8 :: ByteString -> String+decodeUTF8 = toString . fromRep++type SHA256Hash = String++readPackage :: FilePath -> PackageIdentifier -> IO (GenericPackageDescription, SHA256Hash)+readPackage dirPrefix (PackageIdentifier name version) = do+ let cabalFile = dirPrefix </> unPackageName name </> display version </> unPackageName name <.> "cabal"+ buf <- BS.readFile cabalFile+ cabal <- case parsePackageDescription (decodeUTF8 buf) of+ ParseOk _ a -> return a+ ParseFailed err -> fail (cabalFile ++ ": " ++ show err)+ return (cabal, mkSHA256 buf)++mkSHA256 :: ByteString -> SHA256Hash+mkSHA256 = showDigest . sha256 . fromStrict++declareLenses [d|+ data Meta = Meta { hashes :: Map String String+ , locations :: [String]+ , pkgsize :: Int+ }+ deriving (Show)+ |]++instance FromJSON Meta where+ parseJSON (Object v) = Meta+ <$> v .: "package-hashes"+ <*> v .: "package-locations"+ <*> v .: "package-size"+ parseJSON o = fail ("invalid Cabal metadata: " ++ show o)++readPackageMeta :: FilePath -> PackageIdentifier -> IO Meta+readPackageMeta dirPrefix (PackageIdentifier name version) = do+ let metaFile = dirPrefix </> unPackageName name </> display version </> unPackageName name <.> "json"+ buf <- BS.readFile metaFile+ case eitherDecodeStrict buf of+ Left msg -> fail (metaFile ++ ": " ++ msg)+ Right x -> return x
+ hackage2nix/Main.hs view
@@ -0,0 +1,259 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++module Main ( main ) where++import Control.Lens+import Control.Monad+import Control.Monad.Par.Combinator+import Control.Monad.Par.IO+import Control.Monad.Trans ( liftIO )+import Data.List+import Data.Map.Strict ( Map )+import qualified Data.Map.Strict as Map+import Data.Maybe+import Data.Monoid+import Data.Set ( Set )+import qualified Data.Set as Set+import Data.String+import Distribution.Nixpkgs.Fetch+import Distribution.Nixpkgs.Haskell as Derivation+import Distribution.Nixpkgs.Haskell.Constraint+import Distribution.Nixpkgs.Haskell.FromCabal+import Distribution.Nixpkgs.Haskell.FromCabal.Configuration as Config+import Distribution.Nixpkgs.Haskell.FromCabal.Flags+import Distribution.Nixpkgs.Meta+import Distribution.Nixpkgs.PackageMap+import Distribution.Package+import Distribution.PackageDescription hiding ( options, buildDepends, extraLibs, buildTools )+import Distribution.System+import Distribution.Text+import Distribution.Version+import HackageGit+import Language.Nix+import Options.Applicative+import qualified Paths_cabal2nix as Main+import Stackage+import System.FilePath+import System.IO+import Text.PrettyPrint.HughesPJClass hiding ( (<>) )++type PackageSet = Map PackageName Version+type PackageMultiSet = Map PackageName (Set Version)++data CLI = CLI+ { hackageRepository :: FilePath+ , preferredVersionsFile :: Maybe FilePath+ , nixpkgsRepository :: FilePath+ , ltsHaskellRepository :: FilePath+ , stackageNightlyRepository :: FilePath+ , configFile :: FilePath+ , targetPlatform :: Platform+ }+ deriving (Show)++main :: IO ()+main = do+ let cliOptions :: Parser CLI+ cliOptions = CLI+ <$> strOption (long "hackage" <> help "path to Hackage git repository" <> value "hackage" <> showDefaultWith id <> metavar "PATH")+ <*> optional (strOption (long "preferred-versions" <> help "path to Hackage preferred-versions file" <> value "hackage/preferred-versions" <> showDefault <> metavar "PATH"))+ <*> strOption (long "nixpkgs" <> help "path to Nixpkgs repository" <> value "nixpkgs" <> showDefaultWith id <> metavar "PATH")+ <*> strOption (long "lts-haskell" <> help "path to LTS Haskell repository" <> value "lts-haskell" <> showDefaultWith id <> metavar "PATH")+ <*> strOption (long "stackage-nightly" <> help "path to Stackage Nightly repository" <> value "stackage-nightly" <> showDefaultWith id <> metavar "PATH")+ <*> strOption (long "config" <> help "path to configuration file inside of Nixpkgs" <> value "pkgs/development/haskell-modules/configuration-hackage2nix.yaml" <> showDefaultWith id <> metavar "PATH")+ <*> option (fmap fromString str) (long "platform" <> help "target platform to generate package set for" <> value "x86_64-linux" <> showDefaultWith display <> metavar "PLATFORM")++ pinfo :: ParserInfo CLI+ pinfo = info+ ( helper+ <*> infoOption ("hackage2nix " ++ display Main.version) (long "version" <> help "Show version number")+ <*> cliOptions+ )+ ( fullDesc+ <> header "hackage2nix converts a Hackage database into a hackage-packages.nix file."+ )+ CLI {..} <- execParser pinfo++ config' <- readConfiguration (nixpkgsRepository </> configFile)+ nixpkgs <- readNixpkgPackageMap nixpkgsRepository Nothing+ preferredVersions <- readPreferredVersions (fromMaybe (hackageRepository </> "preferred-versions") preferredVersionsFile)+ let fixup = Map.delete "acme-everything" -- TODO: https://github.com/NixOS/cabal2nix/issues/164+ . Map.delete "som" -- TODO: https://github.com/NixOS/cabal2nix/issues/164+ . Map.delete "type" -- TODO: https://github.com/NixOS/cabal2nix/issues/163+ hackage <- fixup <$> readHackage hackageRepository+ snapshots <- runParIO (readLTSHaskell ltsHaskellRepository)+ nightly <- readStackageNightly stackageNightlyRepository+ let+ config :: Configuration+ config = config' { defaultPackageOverrides = [ Dependency n (thisVersion (Stackage.version spec)) | (n, spec) <- Map.toList (packages nightly) ] }++ hackagePackagesFile :: FilePath+ hackagePackagesFile = nixpkgsRepository </> "pkgs/development/haskell-modules/hackage-packages.nix"++ corePackageSet :: PackageSet+ corePackageSet = Map.fromList [ (name, v) | PackageIdentifier name v <- Set.toList (Config.corePackages config) ]++ latestVersionSet :: PackageSet+ latestVersionSet = Map.map Set.findMax (Map.filter (not . Set.null) (Map.mapWithKey (enforcePreferredVersions preferredVersions) hackage))++ defaultPackageOverridesSet :: PackageSet+ defaultPackageOverridesSet = Map.fromList [ (name, resolveConstraint c hackage) | c@(Dependency name _) <- defaultPackageOverrides config ]++ generatedDefaultPackageSet :: PackageSet+ generatedDefaultPackageSet = (defaultPackageOverridesSet `Map.union` latestVersionSet) `Map.difference` corePackageSet++ latestCorePackageSet :: PackageSet+ latestCorePackageSet = latestVersionSet `Map.intersection` corePackageSet++ latestOverridePackageSet :: PackageSet+ latestOverridePackageSet = latestVersionSet `Map.intersection` defaultPackageOverridesSet++ extraPackageSet :: PackageMultiSet+ extraPackageSet = Map.unionsWith Set.union+ [ Map.singleton name (Set.singleton (resolveConstraint c hackage)) | c@(Dependency name _) <- extraPackages config ]++ stackagePackageSet :: Map PackageName (Map Version Spec)+ stackagePackageSet = Map.fromListWith (Map.unionWith mergeSpecs) [ (n, Map.singleton (Stackage.version spec) spec) | snapshot <- nightly:snapshots, (n, spec) <- Map.toList (packages snapshot) ]++ db :: PackageMultiSet+ db = Map.unionsWith Set.union [ Map.map Set.singleton generatedDefaultPackageSet+ , Map.map Set.singleton latestCorePackageSet+ , Map.map Set.singleton latestOverridePackageSet+ , extraPackageSet+ , Map.map Map.keysSet stackagePackageSet+ ]++ haskellResolver :: Dependency -> Bool+ haskellResolver (Dependency name vrange)+ | Just v <- Map.lookup name corePackageSet = v `withinRange` vrange+ | Just v <- Map.lookup name generatedDefaultPackageSet = v `withinRange` vrange+ | otherwise = False++ nixpkgsResolver :: Identifier -> Maybe Binding+ nixpkgsResolver = resolve (Map.map (Set.map (over path ("pkgs":))) nixpkgs)++ globalPackageMaintainers :: Map PackageName (Set Identifier)+ globalPackageMaintainers = Map.unionsWith Set.union [ Map.singleton p (Set.singleton m) | (m,ps) <- Map.toList (packageMaintainers config), p <- Set.toList ps ]++ pkgs <- runParIO $ flip parMapM (Map.toAscList db) $ \(name, vs) -> do+ defs <- forM (Set.toAscList vs) $ \v -> liftIO $ do+ let pkgId :: PackageIdentifier+ pkgId = PackageIdentifier name v++ (descr, cabalSHA256) <- readPackage hackageRepository pkgId+ meta <- readPackageMeta hackageRepository pkgId++ let isInDefaultPackageSet :: Bool+ isInDefaultPackageSet = maybe False (== v) (Map.lookup name generatedDefaultPackageSet)++ tarballSHA256 :: SHA256Hash+ tarballSHA256 = fromMaybe (error (display pkgId ++ ": meta data has no hash for the tarball"))+ (view (hashes . at "SHA256") meta)++ spec :: Spec+ spec = Spec v True True `fromMaybe` (Map.lookup name stackagePackageSet >>= Map.lookup v)++ flagAssignment :: FlagAssignment -- We don't use the flags from Stackage Nightly here, because+ flagAssignment = configureCabalFlags pkgId -- they are chosen specifically for GHC 7.10.2.++ attr :: String+ attr = if isInDefaultPackageSet then unPackageName name else mangle pkgId++ drv :: Derivation+ drv = fromGenericPackageDescription haskellResolver nixpkgsResolver targetPlatform (compilerInfo config) flagAssignment [] descr+ & src .~ DerivationSource "url" ("mirror://hackage/" ++ display pkgId ++ ".tar.gz") "" tarballSHA256+ & editedCabalFile .~ cabalSHA256+ & Derivation.runHaddock &&~ Stackage.runHaddock spec+ & doCheck &&~ runTests spec+ & metaSection.hydraPlatforms %~ (`Set.difference` Map.findWithDefault Set.empty name (dontDistributePackages config))+ & metaSection.maintainers .~ Map.findWithDefault Set.empty name globalPackageMaintainers+ & metaSection.hydraPlatforms %~ (if isInDefaultPackageSet then id else const Set.empty)++ overrides :: Doc+ overrides = fcat $ punctuate space [ disp b <> semi | b <- Set.toList (view (dependencies . each) drv), not (isFromHackage b) ]+ return $ render $ nest 2 $+ hang (doubleQuotes (text attr) <+> equals <+> text "callPackage") 2 (parens (pPrint drv)) <+> (braces overrides <> semi)++ return (intercalate "\n\n" defs)++ withFile hackagePackagesFile WriteMode $ \h -> do+ hPutStrLn h "/* hackage-packages.nix is an auto-generated file -- DO NOT EDIT! */"+ hPutStrLn h ""+ hPutStrLn h "{ pkgs, stdenv, callPackage }:"+ hPutStrLn h ""+ hPutStrLn h "self: {"+ hPutStrLn h ""+ mapM_ (\pkg -> hPutStrLn h pkg >> hPutStrLn h "") pkgs+ hPutStrLn h "}"++ void $ runParIO $ flip parMapM snapshots $ \Snapshot {..} -> liftIO $ do+ let allPackages :: PackageSet+ allPackages = Map.difference+ (Map.fromList [ (name, Stackage.version spec) | (name, spec) <- Map.toList packages ] `Map.union` generatedDefaultPackageSet)+ corePackages'++ ltsConfigFile :: FilePath+ ltsConfigFile = nixpkgsRepository </> "pkgs/development/haskell-modules/configuration-" ++ show (pPrint snapshot) ++ ".nix"++ corePackages' :: PackageSet+ corePackages' = corePackages `Map.union` Map.fromList [("Cabal", Version [] []), ("rts", Version [] [])]++ withFile ltsConfigFile WriteMode $ \h -> do+ hPutStrLn h "{ pkgs }:"+ hPutStrLn h ""+ hPutStrLn h "with import ./lib.nix { inherit pkgs; };"+ hPutStrLn h ""+ hPutStrLn h "self: super: {"+ hPutStrLn h ""+ hPutStrLn h " # core libraries provided by the compiler"+ forM_ (Map.keys corePackages') $ \n ->+ unless (n == "ghc") (hPutStrLn h (" " ++ unPackageName n ++ " = null;"))+ hPutStrLn h ""+ hPutStrLn h (" # " ++ show (pPrint snapshot) ++ " packages")+ forM_ (Map.toList allPackages) $ \(name, v) -> do+ let pkgId = PackageIdentifier name v++ isInDefaultPackageSet :: Bool+ isInDefaultPackageSet = maybe False (== v) (Map.lookup name generatedDefaultPackageSet)++ isInStackage :: Bool+ isInStackage = isJust (Map.lookup name packages)+ case (isInStackage,isInDefaultPackageSet) of+ (True,True) -> return () -- build is visible and enabled+ (True,False) -> hPutStrLn h (" " ++ show (unPackageName name) ++ " = doDistribute super." ++ show (mangle pkgId) ++ ";")+ (False,True) -> hPutStrLn h (" " ++ show (unPackageName name) ++ " = dontDistribute super." ++ show (unPackageName name) ++ ";")+ (False,False) -> fail ("logic error processing " ++ display pkgId ++ " in " ++ show (pPrint snapshot))+ hPutStrLn h ""+ hPutStrLn h "}"+++isFromHackage :: Binding -> Bool+isFromHackage b = case view (reference . path) b of+ ["self",_] -> True+ _ -> False++readPreferredVersions :: FilePath -> IO [Constraint]+readPreferredVersions p = mapMaybe parsePreferredVersionsLine . lines <$> readFile p++parsePreferredVersionsLine :: String -> Maybe Constraint+parsePreferredVersionsLine [] = Nothing+parsePreferredVersionsLine ('-':'-':_) = Nothing+parsePreferredVersionsLine l = simpleParse l `mplus` error ("invalid preferred-versions line: " ++ show l)++enforcePreferredVersions :: [Constraint] -> PackageName -> Set Version -> Set Version+enforcePreferredVersions cs pkg = Set.filter (\v -> PackageIdentifier pkg v `satisfiesConstraints` cs)++resolveConstraint :: Constraint -> Hackage -> Version+resolveConstraint c = fromMaybe (error msg) . resolveConstraint' c+ where msg = "constraint " ++ display c ++ " cannot be resolved in Hackage"++resolveConstraint' :: Constraint -> Hackage -> Maybe Version+resolveConstraint' (Dependency name vrange) hackage+ | Just vset' <- Map.lookup name hackage+ , vset <- Set.filter (`withinRange` vrange) vset'+ , not (Set.null vset) = Just (Set.findMax vset)+ | otherwise = Nothing++mangle :: PackageIdentifier -> String+mangle (PackageIdentifier (PackageName name) v) = name ++ '_' : [ if c == '.' then '_' else c | c <- display v ]
+ hackage2nix/Stackage.hs view
@@ -0,0 +1,114 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Stackage where++import Control.DeepSeq+import Control.Exception ( assert )+import Control.Monad+import Control.Monad.Par.Combinator+import Control.Monad.Par.IO+import Control.Monad.Trans+import Data.List+import Data.List.Split+import Data.Map as Map+import Data.Maybe+import Data.Time.Calendar+import Data.Yaml+import Distribution.Compiler+import Distribution.Nixpkgs.Haskell.OrphanInstances ( )+import Distribution.Package+import Distribution.Version+import GHC.Generics ( Generic )+import Stackage.Types hiding ( display )+import System.Directory+import System.FilePath+import Text.PrettyPrint.HughesPJClass++data Spec = Spec+ { version :: Version+ -- , flagOverrides :: Map FlagName Bool+ , runTests :: Bool+ , runHaddock :: Bool+ -- , runLinuxBuilds :: Bool+ }+ deriving (Show, Generic)++instance Eq Spec where+ a == b = version a == version b++instance Ord Spec where+ compare a b = compare (version a) (version b)++data Snapshot = Snapshot+ { snapshot :: SnapshotType+ , compiler :: CompilerId+ , corePackages :: Map PackageName Version+ , packages :: Map PackageName Spec+ }+ deriving (Show, Generic)++deriving instance Generic SnapshotType+instance NFData Spec+instance NFData Snapshot+instance NFData SnapshotType++instance Pretty SnapshotType where+ pPrint STNightly = text "stackage-nightly"+ pPrint (STNightly2 _) = text "stackage-nightly"+ pPrint (STLTS m n) = text "lts-" <> int m <> char '.' <> int n++readLTSHaskell :: FilePath -> ParIO [Snapshot]+readLTSHaskell dirPath = do+ filePaths <- liftIO (listFiles dirPath)+ parMapM (liftIO . readSnapshot) [ dirPath </> p | p <- filePaths, takeExtension p == ".yaml" ]++readStackageNightly :: FilePath -> IO Snapshot+readStackageNightly dirPath = do+ filePaths <- liftIO (listFiles dirPath)+ let filePath = maximum [ p | p <- filePaths, takeExtension p == ".yaml" ]+ readSnapshot (dirPath </> filePath)++readSnapshot :: FilePath -> IO Snapshot+readSnapshot p = fmap (fromBuildPlan (parseSnapshotType (takeFileName p))) (readBuildPlan p)++parseSnapshotType :: FilePath -> SnapshotType+parseSnapshotType p+ | "lts-" `isPrefixOf` p+ , [major,minor] <- splitOn "." (drop 4 (dropExtension p))+ = STLTS (read major) (read minor)+ | "nightly-" `isPrefixOf` p+ , [year,month,day] <- splitOn "-" (drop 8 (dropExtension p))+ = STNightly2 (fromGregorian (read year) (read month) (read day))+ | otherwise = error ("parseSnapshotType: invalid file name " ++ p)++readBuildPlan :: FilePath -> IO BuildPlan+readBuildPlan = fmap fromJust . decodeFile++fromBuildPlan :: SnapshotType -> BuildPlan -> Snapshot+fromBuildPlan snt bp = Snapshot snt+ (CompilerId GHC (siGhcVersion (bpSystemInfo bp)))+ (siCorePackages (bpSystemInfo bp))+ (Map.map fromPackagePlan (bpPackages bp))++fromPackagePlan :: PackagePlan -> Spec+fromPackagePlan pp = Spec (ppVersion pp)+ -- (pcFlagOverrides ppc)+ (pcTests ppc == ExpectSuccess)+ (pcHaddocks ppc == ExpectSuccess)+ -- (not (pcSkipBuild ppc))+ where ppc = ppConstraints pp++listFiles :: FilePath -> IO [FilePath]+listFiles path = do+ let isFile p = doesFileExist (path </> p)+ getDirectoryContents path >>= filterM isFile . Prelude.filter (\x -> head x /= '.')++mergeSpecs :: Spec -> Spec -> Spec+mergeSpecs a b = Spec { version = assert (version a == version b) version a+ -- , flagOverrides = flagOverrides a+ , runTests = runTests a && runTests b+ , runHaddock = runHaddock a && runHaddock b+ -- , runLinuxBuilds = runLinuxBuilds a+ }
− src/Cabal2Nix/CorePackages.hs
@@ -1,43 +0,0 @@-module Cabal2Nix.CorePackages ( corePackages, coreBuildTools ) where---- | List of packages shipped with ghc and therefore at the moment not in--- nixpkgs. This should probably be configurable at first. Later, it might--- be good to actually include them as dependencies, but set them to null--- if GHC provides them (as different GHC versions vary).------ The commented packages have previously been non-core, so we don't filter--- them.-corePackages :: [String]-corePackages = [- "array",- "base",- "bin-package-db",- "bytestring",- -- "Cabal",- "containers",- "directory",- -- "extensible-exceptions",- "ffi",- -- "filepath",- "ghc",- "ghc-binary",- "ghc-prim",- "haskell2010", -- new as core, but doesn't work in older GHCs anyway- "haskell98",- "hpc",- "integer-gmp",- "old-locale",- "old-time",- "pretty",- "process",- -- "random",- "template-haskell",- -- "time",- "unix"- ]--coreBuildTools :: [String]-coreBuildTools = [- "ghc",- "hsc2hs"- ]
− src/Cabal2Nix/Flags.hs
@@ -1,31 +0,0 @@-module Cabal2Nix.Flags ( configureCabalFlags ) where--import Distribution.Package-import Distribution.PackageDescription--configureCabalFlags :: PackageIdentifier -> FlagAssignment-configureCabalFlags (PackageIdentifier (PackageName name) _)- | name == "arithmoi" = [disable "llvm"]- | name == "accelerate-examples"= [disable "opencl"]- | name == "diagrams-builder" = [enable "cairo", enable "svg", enable "ps", enable "rasterific"]- | name == "folds" = [disable "test-hlint"]- | name == "git-annex" = [enable "Assistant" , enable "Production"]- | name == "haskeline" = [enable "terminfo"]- | name == "haste-compiler" = [enable "portable"]- | name == "hslua" = [enable "system-lua"]- | name == "hxt" = [enable "network-uri"]- | name == "idris" = [enable "gmp", enable "ffi"]- | name == "io-streams" = [enable "NoInteractiveTests"]- | name == "pandoc" = [enable "https", enable "make-pandoc-man-pages"]- | name == "reactive-banana-wx" = [disable "buildExamples"]- | name == "snap-server" = [enable "openssl"]- | name == "xmobar" = [enable "all_extensions"]- | name == "xmonad-extras" = [disable "with_hlist", enable "with_split", enable "with_parsec"]- | name == "yi" = [enable "pango", enable "vty"]- | otherwise = []--enable :: String -> (FlagName,Bool)-enable name = (FlagName name, True)--disable :: String -> (FlagName,Bool)-disable name = (FlagName name, False)
− src/Cabal2Nix/Generate.hs
@@ -1,66 +0,0 @@-module Cabal2Nix.Generate ( cabal2nix ) where--import Cabal2Nix.Flags-import Cabal2Nix.License-import Cabal2Nix.Normalize-import Cabal2Nix.PostProcess-import Data.Maybe-import Distribution.Compiler-import Distribution.NixOS.Derivation.Cabal-import qualified Distribution.Package as Cabal-import qualified Distribution.PackageDescription as Cabal-import Distribution.PackageDescription.Configuration-import Distribution.System--cabal2nix :: Cabal.GenericPackageDescription -> Derivation-cabal2nix cabal = normalize $ postProcess MkDerivation- { pname = let Cabal.PackageName x = Cabal.pkgName pkg in x- , version = Cabal.pkgVersion pkg- , src = error "cabal2nix left the src field undefined"- , isLibrary = isJust (Cabal.library tpkg)- , isExecutable = not (null (Cabal.executables tpkg))- , extraFunctionArgs = []- , buildDepends = map unDep deps- , testDepends = map unDep tstDeps ++ concatMap Cabal.extraLibs tests- , buildTools = map unDep tools- , extraLibs = libs- , pkgConfDeps = pcs- , configureFlags = []- , cabalFlags = configureCabalFlags pkg- , runHaddock = True- , jailbreak = False- , doCheck = True- , testTarget = ""- , hyperlinkSource = True- , enableSplitObjs = True- , phaseOverrides = ""- , metaSection = Meta- { homepage = Cabal.homepage descr- , description = Cabal.synopsis descr- , license = fromCabalLicense (Cabal.license descr)- , platforms = []- , hydraPlatforms = []- , maintainers = []- }- }- where- descr = Cabal.packageDescription cabal- pkg = Cabal.package descr- deps = Cabal.buildDepends tpkg- tests = map Cabal.testBuildInfo (Cabal.testSuites tpkg)- libDeps = map Cabal.libBuildInfo (maybeToList (Cabal.library tpkg))- exeDeps = map Cabal.buildInfo (Cabal.executables tpkg)- tstDeps = concatMap Cabal.buildTools tests ++ concatMap Cabal.pkgconfigDepends tests ++- concatMap Cabal.targetBuildDepends tests- tools = concatMap Cabal.buildTools (libDeps ++ exeDeps)- libs = concatMap Cabal.extraLibs (libDeps ++ exeDeps)- pcs = map unDep (concatMap Cabal.pkgconfigDepends (libDeps ++ exeDeps))- Right (tpkg, _) = finalizePackageDescription- (configureCabalFlags pkg)- (const True)- (Platform I386 Linux) -- shouldn't be hardcoded- (CompilerId GHC (Version [7,6,3] [])) -- dito- [] cabal--unDep :: Cabal.Dependency -> String-unDep (Cabal.Dependency (Cabal.PackageName x) _) = x
− src/Cabal2Nix/License.hs
@@ -1,27 +0,0 @@-module Cabal2Nix.License ( fromCabalLicense ) where--import Distribution.NixOS.Derivation.License-import Distribution.License ( License(..) )-import Data.Version--fromCabalLicense :: Distribution.License.License -> Distribution.NixOS.Derivation.License.License-fromCabalLicense (GPL Nothing) = Unknown (Just "GPL")-fromCabalLicense (GPL (Just (Version [2] []))) = Known "self.stdenv.lib.licenses.gpl2"-fromCabalLicense (GPL (Just (Version [3] []))) = Known "self.stdenv.lib.licenses.gpl3"-fromCabalLicense (LGPL Nothing) = Unknown (Just "LGPL")-fromCabalLicense (LGPL (Just (Version [2,1] []))) = Known "self.stdenv.lib.licenses.lgpl21"-fromCabalLicense (LGPL (Just (Version [2] []))) = Known "self.stdenv.lib.licenses.lgpl2"-fromCabalLicense (LGPL (Just (Version [3] []))) = Known "self.stdenv.lib.licenses.gpl3"-fromCabalLicense (AGPL Nothing) = Unknown (Just "AGPL")-fromCabalLicense (AGPL (Just (Version [3] []))) = Known "self.stdenv.lib.licenses.agpl3"-fromCabalLicense (AGPL (Just (Version [3,0] []))) = Known "self.stdenv.lib.licenses.agpl3"-fromCabalLicense (UnknownLicense "BSD2") = Known "self.stdenv.lib.licenses.bsd2"-fromCabalLicense BSD3 = Known "self.stdenv.lib.licenses.bsd3"-fromCabalLicense BSD4 = Unknown (Just "BSD4")-fromCabalLicense MIT = Known "self.stdenv.lib.licenses.mit"-fromCabalLicense PublicDomain = Known "self.stdenv.lib.licenses.publicDomain"-fromCabalLicense AllRightsReserved = Known "self.stdenv.lib.licenses.unfree"-fromCabalLicense (Apache Nothing) = Known "self.stdenv.lib.licenses.asl20"-fromCabalLicense (Apache (Just (Version [2,0] []))) = Known "self.stdenv.lib.licenses.asl20"-fromCabalLicense OtherLicense = Unknown Nothing-fromCabalLicense l = error $ "Cabal2Nix.License.fromCabalLicense: unknown license " ++ show l
− src/Cabal2Nix/Name.hs
@@ -1,131 +0,0 @@-module Cabal2Nix.Name ( toNixName, libNixName, buildToolNixName ) where--import Data.Char---- | Map Cabal names to Nix attribute names.-toNixName :: String -> String-toNixName [] = error "toNixName: empty string is not a valid argument"-toNixName name = f name- where- f [] = []- f ('-':c:cs) | c `notElem` "-" = toUpper c : f cs- f ('-':_) = error ("unexpected package name " ++ show name)- f (c:cs) = c : f cs---- | Map libraries to Nix packages.--- TODO: This should probably be configurable. We also need to consider the--- possibility of name clashes with Haskell libraries. I have included--- identity mappings to incicate that I have verified their correctness.-libNixName :: String -> [String]-libNixName "adns" = return "adns"-libNixName "alsa" = return "alsaLib"-libNixName "appindicator-0.1" = return "appindicator"-libNixName "appindicator3-0.1" = return "appindicator"-libNixName "asound" = return "alsaLib"-libNixName "awesomium-1.6.5" = return "awesomium"-libNixName "bz2" = return "bzip2"-libNixName "cairo-pdf" = return "cairo"-libNixName "cairo-ps" = return "cairo"-libNixName "cairo" = return "cairo"-libNixName "cairo-svg" = return "cairo"-libNixName "CEGUIBase-0.7.7" = return "CEGUIBase"-libNixName "CEGUIOgreRenderer-0.7.7" = return "CEGUIOgreRenderer"-libNixName "clutter-1.0" = return "clutter"-libNixName "crypto" = return "openssl"-libNixName "crypt" = [] -- provided by glibc-libNixName "c++" = [] -- What is that?-libNixName "dl" = [] -- provided by glibc-libNixName "gconf-2.0" = return "gconf"-libNixName "gdk-2.0" = return "gtk"-libNixName "gdk-pixbuf-2.0" = return "gdk_pixbuf"-libNixName "gdk-x11-2.0" = return "gdk_x11"-libNixName "gio-2.0" = return "glib"-libNixName "glib-2.0" = return "glib"-libNixName "GL" = return "mesa"-libNixName "GLU" = ["freeglut","mesa"]-libNixName "glut" = ["freeglut","mesa"]-libNixName "gmime-2.4" = return "gmime"-libNixName "gnome-keyring-1" = return "gnome_keyring"-libNixName "gnome-keyring" = return "gnome_keyring"-libNixName "gnome-vfs-2.0" = return "gnome_vfs"-libNixName "gnome-vfs-module-2.0" = return "gnome_vfs_module"-libNixName "gobject-2.0" = return "glib"-libNixName "gstreamer-0.10" = return "gstreamer"-libNixName "gstreamer-audio-0.10" = return "gstreamer-audio"-libNixName "gstreamer-base-0.10" = return "gstreamer-base"-libNixName "gstreamer-controller-0.10" = return "gstreamer-controller"-libNixName "gstreamer-dataprotocol-0.10" = return "gstreamer-dataprotocol"-libNixName "gstreamer-net-0.10" = return "gstreamer-net"-libNixName "gstreamer-plugins-base-0.10" = return "gstreamer-plugins-base"-libNixName "gthread-2.0" = return "glib"-libNixName "gtk+-2.0" = return "gtk"-libNixName "gtk+-3.0" = return "gtk3"-libNixName "gtkglext-1.0" = return "gtkglext"-libNixName "gtksourceview-2.0" = return "gtksourceview"-libNixName "gtksourceview-3.0" = return "gtksourceview"-libNixName "gtk-x11-2.0" = return "gtk_x11"-libNixName "icudata" = return "icu"-libNixName "icui18n" = return "icu"-libNixName "icuuc" = return "icu"-libNixName "idn" = return "libidn"-libNixName "IL" = return "libdevil"-libNixName "iw" = return "wirelesstools"-libNixName "jack" = return "jack2"-libNixName "jpeg" = return "libjpeg"-libNixName "libglade-2.0" = return "libglade"-libNixName "libgsasl" = return "gsasl"-libNixName "librsvg-2.0" = return "librsvg"-libNixName "libsoup-gnome-2.4" = return "libsoup"-libNixName "libusb-1.0" = return "libusb"-libNixName "libxml-2.0" = return "libxml2"-libNixName "libzip" = return "libzip"-libNixName "libzmq" = return "zeromq"-libNixName "m" = [] -- in stdenv-libNixName "mono-2.0" = return "mono"-libNixName "ncursesw" = return "ncurses"-libNixName "notify" = return "libnotify"-libNixName "panelw" = return "ncurses"-libNixName "pangocairo" = return "pango"-libNixName "pcap" = return "libpcap"-libNixName "pcre" = return "pcre"-libNixName "pfs-1.2" = return "pfstools"-libNixName "png" = return "libpng"-libNixName "poppler-glib" = return "popplerGlib"-libNixName "portaudio-2.0" = return "portaudio"-libNixName "pq" = return "postgresql"-libNixName "pthread" = []-libNixName "python-3.3" = return "python3"-libNixName "ruby1.8" = return "ruby"-libNixName "sane-backends" = return "saneBackends"-libNixName "SDL2-2.0" = return "SDL2"-libNixName "sdl2" = return "SDL2"-libNixName "sndfile" = return "libsndfile"-libNixName "sqlite3" = return "sqlite"-libNixName "ssl" = return "openssl"-libNixName "stdc++.dll" = [] -- What is that?-libNixName "stdc++" = [] -- What is that?-libNixName "systemd-journal" = return "systemd"-libNixName "vte-2.90" = return "vte"-libNixName "webkit-1.0" = return "webkit"-libNixName "webkitgtk-3.0" = return "webkitgtk"-libNixName "X11" = return "libX11"-libNixName "Xext" = return "libXext"-libNixName "xft" = return "libXft"-libNixName "Xi" = return "libXi"-libNixName "xml2" = return "libxml2"-libNixName "Xpm" = return "libXpm"-libNixName "Xrandr" = return "libXrandr"-libNixName "Xss" = return "libXScrnSaver"-libNixName "Xtst" = return "libXtst"-libNixName "Xxf86vm" = return "libXxf86vm"-libNixName "zmq" = return "zeromq"-libNixName "z" = return "zlib"-libNixName x = return x---- | Map build tool names to Nix attribute names.-buildToolNixName :: String -> [String]-buildToolNixName "cabal" = return "cabalInstall"-buildToolNixName "gtk2hsC2hs" = return "gtk2hsBuildtools"-buildToolNixName "gtk2hsHookGenerator" = return "gtk2hsBuildtools"-buildToolNixName "gtk2hsTypeGen" = return "gtk2hsBuildtools"-buildToolNixName x = return (toNixName x)
− src/Cabal2Nix/Normalize.hs
@@ -1,70 +0,0 @@-{-# LANGUAGE RecordWildCards #-}--module Cabal2Nix.Normalize ( normalize, normalizeList ) where--import Distribution.NixOS.Derivation.Cabal-import Cabal2Nix.Name-import Cabal2Nix.CorePackages-import Data.List-import Data.Char-import Data.Function-import Distribution.NixOS.Regex ( regsubmatch )--normalize :: Derivation -> Derivation-normalize deriv@(MkDerivation {..}) = deriv- { buildDepends = normalizeNixNames (filter (`notElem` (pname : corePackages)) buildDepends)- , testDepends = normalizeNixNames (filter (`notElem` (pname : corePackages)) testDepends)- , buildTools = normalizeNixBuildTools (filter (`notElem` coreBuildTools) buildTools)- , extraLibs = normalizeNixLibs extraLibs- , pkgConfDeps = normalizeNixLibs pkgConfDeps- , metaSection = normalizeMeta metaSection- }--normalizeMeta :: Meta -> Meta-normalizeMeta meta@(Meta {..}) = meta- { description = normalizeDescription description- , maintainers = normalizeMaintainers maintainers- , platforms = normalizePlatforms platforms- }--normalizeDescription :: String -> String-normalizeDescription desc- | null desc = []- | last desc == '.' && length (filter ('.'==) desc) == 1 = normalizeDescription (init desc)- | otherwise = quote (unwords (words desc))--quote :: String -> String-quote ('\\':c:cs) = '\\' : c : quote cs-quote ('"':cs) = '\\' : '"' : quote cs-quote (c:cs) = c : quote cs-quote [] = []--normalizeList :: [String] -> [String]-normalizeList = nub . sortBy (compare `on` map toLower)--normalizeNixNames :: [String] -> [String]-normalizeNixNames = normalizeList . map toNixName--normalizeNixLibs :: [String] -> [String]-normalizeNixLibs = normalizeList . concatMap libNixName--normalizeNixBuildTools :: [String] -> [String]-normalizeNixBuildTools = normalizeList . concatMap buildToolNixName---- |Strip the "self.ghc.meta.platforms" prefix from platform names, filter--- duplicates, and sort the resulting list alphabetically.------ >>> normalizeMaintainers ["self.stdenv.lib.maintainers.foobar", "foobar"]--- ["foobar"]------ >>> normalizeMaintainers ["any.prefix.is.recognized.yo", "abc.def"]--- ["def","yo"]--normalizeMaintainers :: [String] -> [String]-normalizeMaintainers maints = normalizeList- [ (m `regsubmatch` "^([^.].*\\.)?([^.]+)$") !! 1 | m <- maints ]--normalizePlatforms :: [String] -> [String]-normalizePlatforms [] = ["self.ghc.meta.platforms"]-normalizePlatforms plats = normalizeList- [ if '.' `elem` p then p else "self.stdenv.lib.platforms." ++ p | p <- plats ]
− src/Cabal2Nix/Package.hs
@@ -1,145 +0,0 @@-module Cabal2Nix.Package where--import Control.Applicative-import Control.Monad-import Control.Monad.IO.Class-import Control.Monad.Trans.Maybe-import Data.List ( isSuffixOf, isPrefixOf )-import Data.Maybe ( listToMaybe )-import Distribution.NixOS.Derivation.Cabal-import Distribution.NixOS.Fetch-import Distribution.Text ( simpleParse )-import System.Directory ( doesDirectoryExist, doesFileExist, createDirectoryIfMissing, getHomeDirectory, getDirectoryContents )-import System.Exit ( exitFailure )-import System.FilePath ( (</>), (<.>) )-import System.IO ( hPutStrLn, stderr, hPutStr )--import qualified Distribution.Hackage.DB as DB-import qualified Distribution.Package as Cabal-import qualified Distribution.PackageDescription as Cabal-import qualified Distribution.PackageDescription.Parse as Cabal-import qualified Distribution.ParseUtils as ParseUtils--import qualified Control.Exception as Exception--data Package = Package- { source :: DerivationSource- , cabal :: Cabal.GenericPackageDescription- }- deriving (Show)--getPackage :: Maybe String -> Source -> IO Package-getPackage optHackageDB source = do- (derivSource, pkgDesc) <- fetchOrFromDB optHackageDB source- flip Package pkgDesc <$> maybe (sourceFromHackage (sourceHash source) $ showPackageIdentifier pkgDesc) return derivSource---fetchOrFromDB :: Maybe String -> Source -> IO (Maybe DerivationSource, Cabal.GenericPackageDescription)-fetchOrFromDB optHackageDB src- | "cabal://" `isPrefixOf` sourceUrl src = fmap ((,) Nothing) . fromDB optHackageDB . drop (length "cabal://") $ sourceUrl src- | otherwise = do- r <- fetch cabalFromPath src- case r of- Nothing ->- hPutStrLn stderr "*** failed to fetch source. Does the URL exist?" >> exitFailure- Just (derivSource, (externalSource, pkgDesc)) ->- return (derivSource <$ guard externalSource, pkgDesc)--fromDB :: Maybe String -> String -> IO Cabal.GenericPackageDescription-fromDB optHackageDB pkg = do- pkgDesc <- (lookupVersion <=< DB.lookup name) <$> maybe DB.readHackage DB.readHackage' optHackageDB- case pkgDesc of- Just r -> return r- Nothing -> hPutStrLn stderr "*** no such package in the cabal database (did you run cabal update?). " >> exitFailure- where- Just pkgId = simpleParse pkg- Cabal.PackageName name = Cabal.pkgName pkgId- version = Cabal.pkgVersion pkgId-- lookupVersion :: DB.Map DB.Version Cabal.GenericPackageDescription -> Maybe Cabal.GenericPackageDescription- lookupVersion- | null (versionBranch version) = fmap snd . listToMaybe . reverse . DB.toAscList- | otherwise = DB.lookup version---readFileMay :: String -> IO (Maybe String)-readFileMay file = do- e <- doesFileExist file- if e- then Just <$> readFile file- else return Nothing--hashCachePath :: String -> IO String-hashCachePath pid = do- home <- getHomeDirectory- let cacheDir = home </> ".cache/cabal2nix"- createDirectoryIfMissing True cacheDir- return $ cacheDir </> pid <.> "sha256"--sourceFromHackage :: Maybe String -> String -> IO DerivationSource-sourceFromHackage optHash pkgId = do- cacheFile <- hashCachePath pkgId- let cachedHash = MaybeT $ maybe (readFileMay cacheFile) (return . Just) optHash- url = "mirror://hackage/" ++ pkgId ++ ".tar.gz"-- -- Use the cached hash (either from cache file or given on cmdline via sha256 opt)- -- if available, otherwise download from hackage to compute hash.- maybeHash <- runMaybeT $ cachedHash <|> derivHash . fst <$> fetchWith (False, "url", []) (Source url "" Nothing)- case maybeHash of- Just hash ->- -- We need to force the hash here. If we didn't do this, then when reading the- -- hash from the cache file, the cache file will still be open for reading- -- (because lazy io) when writeFile opens the file again for writing. By forcing- -- the hash here, we ensure that the file is closed before opening it again.- seq (length hash) $- DerivationSource "url" url "" hash <$ writeFile cacheFile hash- Nothing -> do- hPutStr stderr $ unlines- [ "*** cannot compute hash. (Not a hackage project?)"- , " If your project is not on hackage, please supply the path to the root directory of"- , " the project, not to the cabal file."- , ""- , " If your project is on hackage but you still want to specify the hash manually, you"- , " can use the --sha256 option."- ]- exitFailure--showPackageIdentifier :: Cabal.GenericPackageDescription -> String-showPackageIdentifier pkgDesc = name ++ "-" ++ showVersion version where- pkgId = Cabal.package . Cabal.packageDescription $ pkgDesc- Cabal.PackageName name = Cabal.packageName pkgId- version = Cabal.packageVersion pkgId--cabalFromPath :: FilePath -> MaybeT IO (Bool, Cabal.GenericPackageDescription)-cabalFromPath path = do- d <- liftIO $ doesDirectoryExist path- (,) d <$> if d- then cabalFromDirectory path- else cabalFromFile False path--cabalFromDirectory :: FilePath -> MaybeT IO Cabal.GenericPackageDescription-cabalFromDirectory dir = do- cabals <- liftIO $ getDirectoryContents dir >>= filterM doesFileExist . map (dir </>) . filter (".cabal" `isSuffixOf`)- case cabals of- [cabalFile] -> cabalFromFile True cabalFile- _ -> liftIO $ hPutStrLn stderr "*** found zero or more than one cabal file. Exiting." >> exitFailure--handleIO :: (Exception.IOException -> IO a) -> IO a -> IO a-handleIO = Exception.handle--cabalFromFile :: Bool -> FilePath -> MaybeT IO Cabal.GenericPackageDescription-cabalFromFile failHard file =- -- readFile throws an error if it's used on binary files which contain sequences- -- that do not represent valid characters. To catch that exception, we need to- -- wrap the whole block in `catchIO`, because of lazy IO. The `case` will force- -- the reading of the file, so we will always catch the expression here.- MaybeT $ handleIO (const $ return Nothing) $ do- content <- readFile file- case Cabal.parsePackageDescription content of- Cabal.ParseFailed e | failHard -> do- let (line, err) = ParseUtils.locatedErrorMsg e- msg = maybe "" ((++ ": ") . show) line ++ err- putStrLn $ "*** error parsing cabal file: " ++ msg- exitFailure- Cabal.ParseFailed _ -> return Nothing- Cabal.ParseOk _ a -> return (Just a)
− src/Cabal2Nix/PostProcess.hs
@@ -1,322 +0,0 @@-{-# LANGUAGE RecordWildCards #-}--module Cabal2Nix.PostProcess ( postProcess ) where--import Data.List-import Distribution.NixOS.Derivation.Cabal--postProcess :: Derivation -> Derivation-postProcess deriv@(MkDerivation {..})- | pname == "aeson" && version > Version [0,7] []- = deriv { buildDepends = "blazeBuilder":buildDepends }- | pname == "Agda" = deriv { buildTools = "emacs":buildTools, phaseOverrides = agdaPostInstall }- | pname == "alex" && version < Version [3,1] []- = deriv { buildTools = "perl":buildTools }- | pname == "alex" && version >= Version [3,1] []- = deriv { buildTools = "perl":"happy":buildTools }- | pname == "bindings-GLFW" = deriv { extraLibs = "libXext":"libXfixes":extraLibs }- | pname == "bits-extras" = deriv { configureFlags = "--ghc-option=-lgcc_s":configureFlags, extraLibs = filter (/= "gcc_s") extraLibs }- | pname == "Cabal" = deriv { phaseOverrides = "preCheck = \"unset GHC_PACKAGE_PATH; export HOME=$NIX_BUILD_TOP\";" }- | pname == "cabal2nix" = deriv { doCheck = True, phaseOverrides = cabal2nixDoCheckHook }- | pname == "cabal-bounds" = deriv { buildTools = "cabalInstall":buildTools }- | pname == "cabal-install" && version >= Version [0,14] []- = deriv { phaseOverrides = cabalInstallPostInstall }- | pname == "cairo" = deriv { extraLibs = "pkgconfig":"libc":"cairo":"zlib":extraLibs }- | pname == "cookie" = deriv { phaseOverrides = cookieDoCheckHook }- | pname == "cuda" = deriv { phaseOverrides = cudaConfigurePhase, extraLibs = "cudatoolkit":"nvidia_x11":"self.stdenv.cc":extraLibs }- | pname == "darcs" = deriv { phaseOverrides = darcsInstallPostInstall }- | pname == "dns" = deriv { testTarget = "spec" }- | pname == "doctest" = deriv { runHaddock = True, phaseOverrides = doctestNoHaddock }- | pname == "editline" = deriv { extraLibs = "libedit":extraLibs }- | pname == "epic" = deriv { extraLibs = "gmp":"boehmgc":extraLibs, buildTools = "happy":buildTools }- | pname == "either" = deriv { runHaddock = True, phaseOverrides = eitherNoHaddock }- | pname == "ghc-heap-view" = deriv { phaseOverrides = ghciPostInstall }- | pname == "ghc-mod" = deriv { phaseOverrides = ghcModPostInstall, buildTools = "emacs":"makeWrapper":buildTools }- | pname == "ghc-parser" = deriv { buildTools = "cpphs":"happy":buildTools, phaseOverrides = ghcParserPatchPhase }- | pname == "ghc-paths" = deriv { phaseOverrides = ghcPathsPatches }- | pname == "ghc-vis" = deriv { phaseOverrides = ghciPostInstall }- | pname == "git-annex" = deriv { phaseOverrides = gitAnnexOverrides, buildTools = "git":"rsync":"gnupg1":"curl":"wget":"lsof":"openssh":"which":"bup":"perl":buildTools }- | pname == "github-backup" = deriv { buildTools = "git":buildTools }- | pname == "glade" = deriv { extraLibs = "pkgconfig":"libc":extraLibs, pkgConfDeps = "gtkC":delete "gtk" pkgConfDeps }- | pname == "glib" = deriv { extraLibs = "pkgconfig":"libc":extraLibs }- | pname == "gloss-raster" = deriv { extraLibs = "llvm":extraLibs }- | pname == "GLUT" = deriv { extraLibs = "glut":"libSM":"libICE":"libXmu":"libXi":"mesa":extraLibs }- | pname == "graphviz" = deriv { testDepends = "systemGraphviz":testDepends }- | pname == "gtk" = deriv { extraLibs = "pkgconfig":"libc":extraLibs }- | pname == "gtkglext" = deriv { pkgConfDeps = "pangox_compat":pkgConfDeps }- | pname == "gtk2hs-buildtools"= deriv { buildDepends = "hashtables":buildDepends }- | pname == "gtksourceview2" = deriv { extraLibs = "pkgconfig":"libc":extraLibs }- | pname == "haddock" && version < Version [2,14] []- = deriv { buildTools = "alex":"happy":buildTools }- | pname == "haddock" = deriv { phaseOverrides = haddockPreCheck }- | pname == "hakyll" = deriv { testDepends = "utillinux":testDepends }- | pname == "happy" = deriv { buildTools = "perl":buildTools }- | pname == "haskeline" = deriv { buildDepends = "utf8String":buildDepends }- | pname == "haskell-src" = deriv { buildTools = "happy":buildTools }- | pname == "haskell-src-meta" = deriv { buildDepends = "uniplate":buildDepends }- | pname == "HFuse" = deriv { phaseOverrides = hfusePreConfigure }- | pname == "highlighting-kate"= highlightingKatePostProcessing deriv- | pname == "hlibgit2" = deriv { testDepends = "git":testDepends }- | pname == "HList" = deriv { buildTools = "diffutils":buildTools }- | pname == "hmatrix" = deriv { extraLibs = "liblapack":"blas": filter (/= "lapack") extraLibs }- | pname == "hmatrix-special" = deriv { extraLibs = "gsl":extraLibs }- | pname == "hoogle" = deriv { testTarget = "--test-option=--no-net" }- | pname == "hspec" = deriv { doCheck = False }- | pname == "hsyslog" = deriv { phaseOverrides = hsyslogNoHaddock }- | pname == "HTTP" && version >= Version [4000,2,14] []- = deriv { runHaddock = True, phaseOverrides = httpNoHaddock }- | pname == "GlomeVec" = deriv { buildTools = "llvm":buildTools }- | pname == "idris" = deriv { buildTools = "happy":buildTools, extraLibs = "gmp":"boehmgc":extraLibs }- | pname == "language-c-quote" = deriv { buildTools = "alex":"happy":buildTools }- | pname == "language-java" = deriv { buildDepends = "syb":buildDepends }- | pname == "leksah-server" = deriv { buildDepends = "process-leksah":buildDepends }- | pname == "lhs2tex" = deriv { extraLibs = "texLive":extraLibs, phaseOverrides = lhs2texPostInstall }- | pname == "libffi" = deriv { extraLibs = delete "ffi" extraLibs }- | pname == "liquid-fixpoint" = deriv { buildTools = "ocaml":buildTools }- | pname == "llvm-base" = deriv { extraLibs = "llvm":extraLibs }- | pname == "llvm-general" = deriv { doCheck = False }- | pname == "llvm-general-pure"= deriv { doCheck = False }- | pname == "MFlow" = deriv { buildTools = "cpphs":buildTools }- | pname == "markdown-unlit" = deriv { runHaddock = True, phaseOverrides = markdownUnlitNoHaddock }- | pname == "multiarg" = deriv { buildDepends = "utf8String":buildDepends }- | pname == "mime-mail" = deriv { extraFunctionArgs = ["sendmail ? \"sendmail\""], phaseOverrides = mimeMailConfigureFlags }- | pname == "mysql" = deriv { buildTools = "mysqlConfig":buildTools, extraLibs = "zlib":extraLibs }- | pname == "ncurses" = deriv { phaseOverrides = ncursesPatchPhase }- | pname == "Omega" = deriv { testDepends = delete "stdc++" testDepends }- | pname == "OpenAL" = deriv { extraLibs = "openal":extraLibs }- | pname == "OpenGL" = deriv { extraLibs = "mesa":"libX11":extraLibs }- | pname == "pandoc" = deriv { buildDepends = "alex":"happy":buildDepends }- | pname == "pango" = deriv { extraLibs = "pkgconfig":"libc":extraLibs }- | pname == "pcap" = deriv { extraLibs = "libpcap":extraLibs }- | pname == "persistent" = deriv { extraLibs = "sqlite3":extraLibs }- | pname == "poppler" = deriv { extraLibs = "libc":extraLibs }- | pname == "purescript" = deriv { testDepends = "nodejs":testDepends }- | pname == "QuickCheck" && version >= Version [2,7,3] []- = deriv { runHaddock = True, phaseOverrides = quickCheckNoHaddock }- | pname == "repa-algorithms" = deriv { extraLibs = "llvm":extraLibs }- | pname == "repa-examples" = deriv { extraLibs = "llvm":extraLibs }- | pname == "saltine" = deriv { extraLibs = map (\x -> if x == "sodium" then "libsodium" else x) extraLibs }- | pname == "SDL-image" = deriv { extraLibs = "SDL_image":extraLibs }- | pname == "SDL-mixer" = deriv { extraLibs = "SDL_mixer":extraLibs }- | pname == "SDL-ttf" = deriv { extraLibs = "SDL_ttf":extraLibs }- | pname == "sloane" = deriv { phaseOverrides = sloanePostInstall }- | pname == "split" && version == Version [0,2,2] []- = deriv { doCheck = True, phaseOverrides = splitDoCheck }- | pname == "structured-haskell-mode" = deriv { buildTools = "emacs":buildTools, phaseOverrides = structuredHaskellModePostInstall }- | pname == "svgcairo" = deriv { extraLibs = "libc":extraLibs }- | pname == "syb" && version == Version [0,4,2] []- = deriv { doCheck = True, phaseOverrides = sybDoCheck }- | pname == "tar" = deriv { runHaddock = True, phaseOverrides = tarNoHaddock }- | pname == "terminfo" = deriv { extraLibs = "ncurses":extraLibs }- | pname == "threadscope" = deriv { configureFlags = "--ghc-options=-rtsopts":configureFlags }- | pname == "thyme" = deriv { buildTools = "cpphs":buildTools }- | pname == "transformers" && version >= Version [0,4,1] []- = deriv { runHaddock = True, phaseOverrides = transformersNoHaddock }- | pname == "tz" = deriv { extraFunctionArgs = ["pkgs_tzdata"], phaseOverrides = "preConfigure = \"export TZDIR=${pkgs_tzdata}/share/zoneinfo\";" }- | pname == "vacuum" = deriv { extraLibs = "ghcPaths":extraLibs }- | pname == "vector" = deriv { configureFlags = "${self.stdenv.lib.optionalString self.stdenv.isi686 \"--ghc-options=-msse2\"}":configureFlags }- | pname == "wxc" = deriv { extraLibs = "wxGTK":"mesa":"libX11":extraLibs, phaseOverrides = wxcPostInstall }- | pname == "wxcore" = deriv { extraLibs = "wxGTK":"mesa":"libX11":extraLibs }- | pname == "X11" && version >= Version [1,6] []- = deriv { extraLibs = "libXinerama":"libXext":"libXrender":extraLibs }- | pname == "X11" = deriv { extraLibs = "libXinerama":"libXext":extraLibs }- | pname == "X11-xft" = deriv { extraLibs = "pkgconfig":"freetype":"fontconfig":extraLibs- , configureFlags = "--extra-include-dirs=${freetype}/include/freetype2":configureFlags- }- | pname == "xmonad" = deriv { phaseOverrides = xmonadPostInstall }- | pname == "yi" = deriv { runHaddock = True, phaseOverrides = yiFixHaddock }- | otherwise = deriv--cudaConfigurePhase :: String-cudaConfigurePhase = unlines- [ "# Perhaps this should be the default in cabal.nix ..."- , "#"- , "# The cudatoolkit provides both 64 and 32-bit versions of the"- , "# library. GHC's linker fails if the wrong version is found first."- , "# We solve this by eliminating lib64 from the path on 32-bit"- , "# platforms and putting lib64 first on 64-bit platforms."- , "libPaths = if self.stdenv.is64bit then \"lib64 lib\" else \"lib\";"- , "configurePhase = ''"- , " for i in Setup.hs Setup.lhs; do"- , " test -f $i && ghc --make $i"- , " done"- , " for p in $extraBuildInputs $propagatedNativeBuildInputs; do"- , " if [ -d \"$p/include\" ]; then"- , " extraLibDirs=\"$extraLibDirs --extra-include-dir=$p/include\""- , " fi"- , " for d in $libPaths; do"- , " if [ -d \"$p/$d\" ]; then"- , " extraLibDirs=\"$extraLibDirs --extra-lib-dir=$p/$d\""- , " fi"- , " done"- , " done"- , " ./Setup configure --verbose --prefix=\"$out\" $libraryProfiling $extraLibDirs $configureFlags"- , "'';"- ]--ghcModPostInstall :: String-ghcModPostInstall = unlines- [ "configureFlags = \"--datasubdir=${self.pname}-${self.version}\";"- , "postInstall = ''"- , " cd $out/share/$pname-$version"- , " make"- , " rm Makefile"- , " cd .."- , " ensureDir \"$out/share/emacs\""- , " mv $pname-$version emacs/site-lisp"- , " wrapProgram $out/bin/ghc-mod --add-flags \\"- , " \"\\$(${self.ghc.GHCGetPackages} ${self.ghc.version} \\\"\\$(dirname \\$0)\\\" \\\"-g -package-db -g\\\")\""- , " wrapProgram $out/bin/ghc-modi --add-flags \\"- , " \"\\$(${self.ghc.GHCGetPackages} ${self.ghc.version} \\\"\\$(dirname \\$0)\\\" \\\"-g -package-db -g\\\")\""- , "'';"- ]--wxcPostInstall :: String-wxcPostInstall = unlines- [ "postInstall = ''"- , " cp -v dist/build/libwxc.so.${self.version} $out/lib/libwxc.so"- , "'';"- ]--cabalInstallPostInstall :: String-cabalInstallPostInstall = unlines- [ "postInstall = ''"- , " mkdir $out/etc"- , " mv bash-completion $out/etc/bash_completion.d"- , "'';"- ]--darcsInstallPostInstall :: String-darcsInstallPostInstall = unlines- [ "postInstall = ''"- , " mkdir -p $out/etc/bash_completion.d"- , " mv contrib/darcs_completion $out/etc/bash_completion.d/darcs"- , "'';"- ]--highlightingKatePostProcessing :: Derivation -> Derivation-highlightingKatePostProcessing deriv@(MkDerivation {..}) = deriv- { phaseOverrides = "prePatch = \"sed -i -e 's|regex-pcre-builtin >= .*|regex-pcre|' highlighting-kate.cabal\";"- , buildDepends = "regex-pcre" : filter (/="regex-pcre-builtin") buildDepends- }--xmonadPostInstall :: String-xmonadPostInstall = unlines- [ "postInstall = ''"- , " shopt -s globstar"- , " mkdir -p $out/share/man/man1"- , " mv \"$out/\"**\"/man/\"*.1 $out/share/man/man1/"- , "'';"- , "patches = ["- , " # Patch to make xmonad use XMONAD_{GHC,XMESSAGE} (if available)."- , " ./xmonad_ghc_var_0.11.patch"- , "];"- ]--yiFixHaddock :: String-yiFixHaddock = "noHaddock = self.stdenv.lib.versionOlder self.ghc.version \"7.8\";"--gitAnnexOverrides :: String-gitAnnexOverrides = unlines- [ "preConfigure = \"export HOME=$TEMPDIR\";"- , "installPhase = \"./Setup install\";"- , "checkPhase = ''"- , " cp dist/build/git-annex/git-annex git-annex"- , " ./git-annex test"- , "'';"- , "propagatedUserEnvPkgs = [git lsof];"- ]--ghciPostInstall :: String-ghciPostInstall = unlines- [ "postInstall = ''"- , " ensureDir \"$out/share/ghci\""- , " ln -s \"$out/share/$pname-$version/ghci\" \"$out/share/ghci/$pname\""- , "'';"- ]--hfusePreConfigure :: String-hfusePreConfigure = unlines- [ "preConfigure = ''"- , " sed -i -e \"s@ Extra-Lib-Dirs: /usr/local/lib@ Extra-Lib-Dirs: ${fuse}/lib@\" HFuse.cabal"- , "'';"- ]--ghcPathsPatches :: String-ghcPathsPatches = "patches = [ ./ghc-paths-nix.patch ];"--lhs2texPostInstall :: String-lhs2texPostInstall = unlines- [ "postInstall = ''"- , " mkdir -p \"$out/share/doc/$name\""- , " cp doc/Guide2.pdf $out/share/doc/$name"- , " mkdir -p \"$out/nix-support\""- , "'';"- ]--ncursesPatchPhase :: String-ncursesPatchPhase = "patchPhase = \"find . -type f -exec sed -i -e 's|ncursesw/||' {} \\\\;\";"--doctestNoHaddock, markdownUnlitNoHaddock :: String-markdownUnlitNoHaddock = "noHaddock = self.stdenv.lib.versionOlder self.ghc.version \"7.4\";"-doctestNoHaddock = markdownUnlitNoHaddock--cabal2nixDoCheckHook :: String-cabal2nixDoCheckHook = "doCheck = self.stdenv.lib.versionOlder \"7.8\" self.ghc.version;"--cookieDoCheckHook :: String-cookieDoCheckHook = "doCheck = self.stdenv.lib.versionOlder \"7.8\" self.ghc.version;"--eitherNoHaddock :: String-eitherNoHaddock = "noHaddock = self.stdenv.lib.versionOlder self.ghc.version \"7.6\";"--httpNoHaddock, quickCheckNoHaddock, tarNoHaddock, transformersNoHaddock, hsyslogNoHaddock :: String-httpNoHaddock = "noHaddock = self.stdenv.lib.versionOlder self.ghc.version \"6.11\";"-quickCheckNoHaddock = httpNoHaddock-tarNoHaddock = httpNoHaddock-transformersNoHaddock = httpNoHaddock-hsyslogNoHaddock = httpNoHaddock--agdaPostInstall :: String-agdaPostInstall = unlines- [ "postInstall = ''"- , " $out/bin/agda -c --no-main $(find $out/share -name Primitive.agda)"- , " $out/bin/agda-mode compile"- , "'';"- ]--structuredHaskellModePostInstall :: String-structuredHaskellModePostInstall = unlines- [ "postInstall = ''"- , " emacs -L elisp --batch -f batch-byte-compile \"elisp/\"*.el"- , " install -d $out/share/emacs/site-lisp"- , " install \"elisp/\"*.el \"elisp/\"*.elc $out/share/emacs/site-lisp"- , "'';"- ]--sloanePostInstall :: String-sloanePostInstall = unlines- [ "postInstall = ''"- , " mkdir -p $out/share/man/man1"- , " cp sloane.1 $out/share/man/man1/"- , "'';"- ]--mimeMailConfigureFlags :: String-mimeMailConfigureFlags = unlines- [ "configureFlags = \"--ghc-option=-DMIME_MAIL_SENDMAIL_PATH=\\\"${sendmail}\\\"\";"- ]--sybDoCheck, splitDoCheck :: String-sybDoCheck = "doCheck = self.stdenv.lib.versionOlder self.ghc.version \"7.9\";"-splitDoCheck = sybDoCheck--haddockPreCheck :: String-haddockPreCheck = "preCheck = \"unset GHC_PACKAGE_PATH\";"--ghcParserPatchPhase :: String-ghcParserPatchPhase = unlines- [ "patchPhase = ''"- , " substituteInPlace build-parser.sh --replace \"/bin/bash\" \"$SHELL\""- , "'';"- ]
− src/Cabal2Nix/Version.hs
@@ -1,7 +0,0 @@-module Cabal2Nix.Version where--import Data.Version (showVersion)-import Paths_cabal2nix (version)--version :: String-version = showVersion Paths_cabal2nix.version
− src/Distribution/NixOS/Derivation/Cabal.hs
@@ -1,195 +0,0 @@-{-# LANGUAGE PatternGuards, RecordWildCards, CPP #-}-{- |- Module : Distribution.NixOS.Derivation.Cabal- License : BSD3-- Maintainer : nix-dev@cs.uu.nl- Stability : provisional- Portability : PatternGuards-- A represtation of Nix expressions based on Cabal builder defined in- @pkgs\/development\/libraries\/haskell\/cabal\/cabal.nix@.--}--module Distribution.NixOS.Derivation.Cabal- ( Derivation(..)- , parseDerivation- , DerivationSource(..)- , module Distribution.NixOS.Derivation.Meta- , module Data.Version- )- where--import Control.DeepSeq-import Data.Char-import Data.Function-import Data.List-import Data.Version-import Distribution.NixOS.Derivation.Meta-import Distribution.NixOS.Fetch-import Distribution.NixOS.PrettyPrinting-import Distribution.NixOS.Regex hiding ( empty )-import Distribution.Package-#ifdef __HADDOCK__-import Distribution.PackageDescription ( PackageDescription )-#endif-import Distribution.PackageDescription ( FlagAssignment, FlagName(..) )-import Distribution.Text---- | A represtation of Nix expressions for building Haskell packages.--- The data type correspond closely to the definition of--- 'PackageDescription' from Cabal.------ Note that the "Text" instance definition provides pretty-printing,--- but no parsing as of now!-data Derivation = MkDerivation- { pname :: String- , version :: Version- , src :: DerivationSource- , isLibrary :: Bool- , isExecutable :: Bool- , extraFunctionArgs :: [String]- , buildDepends :: [String]- , testDepends :: [String]- , buildTools :: [String]- , extraLibs :: [String]- , pkgConfDeps :: [String]- , configureFlags :: [String]- , cabalFlags :: FlagAssignment- , runHaddock :: Bool- , jailbreak :: Bool- , doCheck :: Bool- , testTarget :: String- , hyperlinkSource :: Bool- , enableSplitObjs :: Bool- , phaseOverrides :: String- , metaSection :: Meta- }- deriving (Show, Eq, Ord)--instance Text Derivation where- disp = renderDerivation- parse = error "parsing Distribution.NixOS.Derivation.Cabal.Derivation is not supported yet"--instance Package Derivation where- packageId deriv = PackageIdentifier (PackageName (pname deriv)) (version deriv)--instance NFData Derivation where- rnf (MkDerivation a b c d e f g h i j k l m n o p q r t u v) =- a `deepseq` b `deepseq` c `deepseq` d `deepseq` e `deepseq` f `deepseq` g `deepseq`- h `deepseq` i `deepseq` j `deepseq` k `deepseq` l `deepseq` m `deepseqFlagAssignment` n `deepseq`- o `deepseq` p `deepseq` q `deepseq` r `deepseq` t `deepseq` u `deepseq` v `deepseq` ()---- FlagName has no NFData instance in old version of Cabal.-deepseqFlagAssignment :: FlagAssignment -> a -> a-deepseqFlagAssignment [] b = b-deepseqFlagAssignment ((FlagName n, v):as) b = n `deepseq` v `deepseq` as `deepseqFlagAssignment` b--renderDerivation :: Derivation -> Doc-renderDerivation deriv =- text "# This file was auto-generated by cabal2nix. Please do NOT edit manually!" $$- text "" $$- funargs (map text ("cabal" : inputs)) $$ vcat- [ text ""- , text "cabal.mkDerivation" <+> lparen <> text "self" <> colon <+> lbrace- , nest 2 $ vcat- [ attr "pname" $ string (pname deriv)- , attr "version" $ doubleQuotes (disp (version deriv))- , sourceAttr (src deriv)- , boolattr "isLibrary" (not (isLibrary deriv) || isExecutable deriv) (isLibrary deriv)- , boolattr "isExecutable" (not (isLibrary deriv) || isExecutable deriv) (isExecutable deriv)- , listattr "buildDepends" empty (buildDepends deriv)- , listattr "testDepends" empty (testDepends deriv)- , listattr "buildTools" empty (buildTools deriv)- , listattr "extraLibraries" empty (extraLibs deriv)- , listattr "pkgconfigDepends" empty (pkgConfDeps deriv)- , onlyIf renderedFlags $ attr "configureFlags" $ doubleQuotes (sep renderedFlags)- , boolattr "enableSplitObjs" (not (enableSplitObjs deriv)) (enableSplitObjs deriv)- , boolattr "noHaddock" (not (runHaddock deriv)) (not (runHaddock deriv))- , boolattr "jailbreak" (jailbreak deriv) (jailbreak deriv)- , boolattr "doCheck" (not (doCheck deriv)) (doCheck deriv)- , onlyIf (testTarget deriv) $ attr "testTarget" $ string (testTarget deriv)- , boolattr "hyperlinkSource" (not (hyperlinkSource deriv)) (hyperlinkSource deriv)- , onlyIf (phaseOverrides deriv) $ vcat ((map text . lines) (phaseOverrides deriv))- , disp (metaSection deriv)- ]- , rbrace <> rparen- , text ""- ]- where- inputs = nub $ sortBy (compare `on` map toLower) $ filter (/="cabal") $ filter (not . isPrefixOf "self.") $- buildDepends deriv ++ testDepends deriv ++ buildTools deriv ++ extraLibs deriv ++ pkgConfDeps deriv ++ extraFunctionArgs deriv- ++ ["fetch" ++ derivKind (src deriv) | derivKind (src deriv) /= "" && not isHackagePackage]- renderedFlags = [ text "-f" <> (if enable then empty else char '-') <> text f | (FlagName f, enable) <- cabalFlags deriv ]- ++ map text (configureFlags deriv)- isHackagePackage = "mirror://hackage/" `isPrefixOf` derivUrl (src deriv)- sourceAttr (DerivationSource{..})- | isHackagePackage = attr "sha256" $ string derivHash- | derivKind /= "" = vcat- [ text "src" <+> equals <+> text ("fetch" ++ derivKind) <+> lbrace- , nest 2 $ vcat- [ attr "url" $ string derivUrl- , attr "sha256" $ string derivHash- , if derivRevision /= "" then attr "rev" (string derivRevision) else empty- ]- , rbrace <> semi- ]- | otherwise = attr "src" $ text derivUrl---- | A very incomplete parser that extracts 'pname', 'version',--- 'sha256', 'platforms', 'hydraPlatforms', 'maintainers', 'doCheck',--- 'jailbreak', and 'runHaddock' from the given Nix expression.-parseDerivation :: String -> Maybe Derivation-parseDerivation buf- | buf =~ "cabal.mkDerivation"- , [name] <- buf `regsubmatch` "pname *= *\"([^\"]+)\""- , [vers'] <- buf `regsubmatch` "version *= *\"([^\"]+)\""- , Just vers <- simpleParse vers'- , sha <- buf `regsubmatch` "sha256 *= *\"([^\"]+)\""- , sr <- buf `regsubmatch` "src *= *([^;]+);"- , url <- buf `regsubmatch` "url *= *\"?([^;\"]+)\"? *;"- , rev <- buf `regsubmatch` "rev *= *\"([^\"]+)\""- , hplats <- buf `regsubmatch` "hydraPlatforms *= *([^;]+);"- , plats <- buf `regsubmatch` "platforms *= *([^;]+);"- , maint <- buf `regsubmatch` "maintainers *= *(with [^;]+;)? \\[([^\"]+)]"- , noHaddock <- buf `regsubmatch` "noHaddock *= *(true|false) *;"- , jailBreak <- buf `regsubmatch` "jailbreak *= *(true|false) *;"- , docheck <- buf `regsubmatch` "doCheck *= *(true|false) *;"- , hyperlSrc <- buf `regsubmatch` "hyperlinkSource *= *(true|false) *;"- , splitObj <- buf `regsubmatch` "enableSplitObjs *= *(true|false) *;"- = Just MkDerivation- { pname = name- , version = vers- , src = case (sr,url) of- ([] , _ ) -> DerivationSource "url" ("mirror://hackage/" ++ name ++ "-" ++ vers' ++ ".tar.gz") "" $ head sha- (sr':_, [] ) -> DerivationSource "" sr' "" ""- (sr':_, url':_ ) -> DerivationSource (drop (length "fetch") . head . words $ sr')- url' (head $ rev ++ [""]) $ head sha-- , isLibrary = False- , isExecutable = False- , extraFunctionArgs = []- , buildDepends = []- , testDepends = []- , buildTools = []- , extraLibs = []- , pkgConfDeps = []- , configureFlags = []- , cabalFlags = []- , runHaddock = noHaddock /= ["true"]- , jailbreak = jailBreak == ["true"]- , doCheck = docheck == ["true"] || null docheck- , testTarget = ""- , hyperlinkSource = hyperlSrc == ["true"] || null hyperlSrc- , enableSplitObjs = splitObj /= ["false"]- , phaseOverrides = ""- , metaSection = Meta- { homepage = ""- , description = ""- , license = Unknown Nothing- , maintainers = if null maint then [] else concatMap words (tail maint)- , platforms = concatMap words (map (map (\c -> if c == '+' then ' ' else c)) plats)- , hydraPlatforms = concatMap words (map (map (\c -> if c == '+' then ' ' else c)) hplats)- }- }- | otherwise = Nothing
− src/Distribution/NixOS/Derivation/License.hs
@@ -1,56 +0,0 @@-{- |- Module : Distribution.NixOS.Derivation.License- License : BSD3-- Maintainer : nix-dev@cs.uu.nl- Stability : provisional- Portability : portable-- Known licenses in Nix expressions are represented using the- attributes defined in @pkgs\/lib\/licenses.nix@, and unknown licenses- are represented as a literal string.- -}--module Distribution.NixOS.Derivation.License ( License(..) ) where--import Control.DeepSeq-import Data.Maybe-import Distribution.NixOS.PrettyPrinting-import Distribution.Text---- | The representation for licenses used in Nix derivations. Known--- licenses are Nix expressions -- such as @stdenv.lib.licenses.bsd3@--- --, so their exact \"name\" is not generally known, because the path--- to @stdenv@ depends on the context defined in the expression. In--- Cabal expressions, for example, the BSD3 license would have to be--- referred to as @self.stdenv.lib.licenses.bsd3@. Other expressions,--- however, use different paths to the @licenses@ record.. Because of--- this station, this library cannot provide an abstract data type that--- encompasses all known licenses. Instead, the @License@ type just--- distinguishes references to known and unknown licenses. The--- difference between the two is in the way they are pretty-printed:------ > > putStrLn (display (Known "stdenv.lib.license.gpl2"))--- > stdenv.lib.license.gpl2--- >--- > > putStrLn (display (Unknown (Just "GPL")))--- > "GPL"--- >--- > > putStrLn (display (Unknown Nothing))--- > "unknown"------ Note that the "Text" instance definition provides pretty-printing,--- but no parsing as of now!--data License = Known String- | Unknown (Maybe String)- deriving (Show, Eq, Ord)--instance Text License where- disp (Known x) = text x- disp (Unknown x) = string (fromMaybe "unknown" x)- parse = error "parsing Distribution.NixOS.Derivation.License is not supported yet"--instance NFData License where- rnf (Known s) = rnf s- rnf (Unknown s) = rnf s
− src/Distribution/NixOS/Derivation/Meta.hs
@@ -1,80 +0,0 @@-{- |- Module : Distribution.NixOS.Derivation.Meta- License : BSD3-- Maintainer : nix-dev@cs.uu.nl- Stability : provisional- Portability : portable-- A representation of the @meta@ section used in Nix expressions. A- detailed description can be found in section 4, \"Meta-attributes\",- of the Nixpkgs manual at <http://nixos.org/nixpkgs/docs.html>.- -}--module Distribution.NixOS.Derivation.Meta- ( Meta(..)- , module Distribution.NixOS.Derivation.License- )- where--import Control.DeepSeq-import Distribution.NixOS.Derivation.License-import Distribution.NixOS.PrettyPrinting-import Distribution.Text---- | A representation of the @meta@ section used in Nix expressions.------ >>> :{--- putStrLn (display (Meta "http://example.org" "an example package" (Unknown Nothing)--- ["stdenv.lib.platforms."++x | x <- ["unix","cygwin"]]--- ["stdenv.lib.platforms.none"]--- ["joe","jane"]))--- :}--- meta = {--- homepage = "http://example.org";--- description = "an example package";--- license = "unknown";--- platforms = stdenv.lib.platforms.unix ++ stdenv.lib.platforms.cygwin;--- hydraPlatforms = stdenv.lib.platforms.none;--- maintainers = with self.stdenv.lib.maintainers; [ joe jane ];--- };------ Note that the "Text" instance definition provides pretty-printing,--- but no parsing as of now!--data Meta = Meta- { homepage :: String -- ^ URL of the package homepage- , description :: String -- ^ short description of the package- , license :: License -- ^ licensing terms- , platforms :: [String] -- ^ list of supported platforms (from @pkgs\/lib\/platforms.nix@)- , hydraPlatforms :: [String] -- ^ list of platforms built by Hydra (from @pkgs\/lib\/platforms.nix@)- , maintainers :: [String] -- ^ list of maintainers from @pkgs\/lib\/maintainers.nix@- }- deriving (Show, Eq, Ord)--instance Text Meta where- disp = renderMeta- parse = error "parsing Distribution.NixOS.Derivation.Cabal.Meta is not supported yet"--instance NFData Meta where- rnf (Meta a b c d e f) = a `deepseq` b `deepseq` c `deepseq` d `deepseq` e `deepseq` f `deepseq` ()--renderMeta :: Meta -> Doc-renderMeta meta = vcat- [ text "meta" <+> equals <+> lbrace- , nest 2 $ vcat- [ onlyIf (homepage meta) $ attr "homepage" $ string (homepage meta)- , onlyIf (description meta) $ attr "description" $ string (description meta)- , attr "license" $ disp (license meta)- , onlyIf (platforms meta) $ sep- [ text "platforms" <+> equals, renderPlatformList (platforms meta) ]- , onlyIf (hydraPlatforms meta) $ sep- [ text "hydraPlatforms" <+> equals, renderPlatformList (hydraPlatforms meta) ]- , listattr "maintainers" (text "with self.stdenv.lib.maintainers;") (maintainers meta)- ]- , rbrace <> semi- ]--renderPlatformList :: [String] -> Doc-renderPlatformList plats =- nest 2 (fsep $ punctuate (text " ++") $ map text plats) <> semi
− src/Distribution/NixOS/Fetch.hs
@@ -1,142 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-module Distribution.NixOS.Fetch- ( Source(..)- , DerivationSource(..), fromDerivationSource- , fetch- , fetchWith- ) where--import Control.Applicative-import Control.DeepSeq-import Control.Monad-import Control.Monad.IO.Class-import Control.Monad.Trans.Maybe-import Data.Maybe-import System.Directory-import System.Environment-import System.Exit-import System.IO-import System.Process---- | A source is a location from which we can fetch, such as a HTTP URL, a GIT URL, ....-data Source = Source- { sourceUrl :: String -- ^ URL to fetch from.- , sourceRevision :: String -- ^ Revision to use. For protocols where this doesn't make sense (such as HTTP), this- -- should be the empty string.- , sourceHash :: Maybe String -- ^ The expected hash of the source, if available.- } deriving (Show, Eq, Ord)---- | A source for a derivation. It always needs a hash and also has a protocol attached to it (url, git, svn, ...).--- A @DerivationSource@ also always has it's revision fully resolved (not relative revisions like @master@, @HEAD@, etc).-data DerivationSource = DerivationSource- { derivKind :: String -- ^ The kind of the source. The name of the build-support fetch derivation should be fetch<kind>.- , derivUrl :: String -- ^ URL to fetch from.- , derivRevision :: String -- ^ Revision to use. Leave empty if the fetcher doesn't support revisions.- , derivHash :: String -- ^ The hash of the source.- } deriving (Show, Eq, Ord)--instance NFData DerivationSource where- rnf (DerivationSource a b c d) = a `deepseq` b `deepseq` c `deepseq` d `deepseq` ()--fromDerivationSource :: DerivationSource -> Source-fromDerivationSource DerivationSource{..} = Source derivUrl derivRevision $ Just derivHash---- | Fetch a source, trying any of the various nix-prefetch-* scripts.-fetch :: forall a. (String -> MaybeT IO a) -- ^ This function is passed the output path name as an argument.- -- It should return 'Nothing' if the file doesn't match the expected format.- -- This is required, because we cannot always check if a download succeeded otherwise.- -> Source -- ^ The source to fetch from.- -> IO (Maybe (DerivationSource, a)) -- ^ The derivation source and the result of the processing function. Returns Nothing if the download failed.-fetch f = runMaybeT . fetchers where- fetchers :: Source -> MaybeT IO (DerivationSource, a)- fetchers source = msum . (fetchLocal source :) $ map (\fetcher -> fetchWith fetcher source >>= process)- [ (False, "zip", [])- , (False, "url", [])- , (True, "git", ["--fetch-submodules"])- , (True, "hg", [])- , (True, "svn", [])- , (True, "bzr", [])- ]-- -- | Remove '/' from the end of the path. Nix doesn't accept paths that- -- end in a slash.- stripSlashSuffix :: String -> String- stripSlashSuffix = reverse . dropWhile (== '/') . reverse-- fetchLocal :: Source -> MaybeT IO (DerivationSource, a)- fetchLocal src = do- let path = stripSlashSuffix $ stripPrefix "file://" $ sourceUrl src- existsFile <- liftIO $ doesFileExist path- existsDir <- liftIO $ doesDirectoryExist path- guard $ existsDir || existsFile- let path' | '/' `elem` path = path- | otherwise = "./" ++ path- process (DerivationSource "" path' "" "", path') <|> localArchive path'-- localArchive :: FilePath -> MaybeT IO (DerivationSource, a)- localArchive path = do- absolutePath <- liftIO $ canonicalizePath path- unpacked <- snd <$> fetchWith (False, "zip", []) (Source ("file://" ++ absolutePath) "" Nothing)- process (DerivationSource "" absolutePath "" "", unpacked)-- process :: (DerivationSource, FilePath) -> MaybeT IO (DerivationSource, a)- process (derivSource, file) = (,) derivSource <$> f file---- | Like 'fetch', but allows to specify which script to use.-fetchWith :: (Bool, String, [String]) -> Source -> MaybeT IO (DerivationSource, FilePath)-fetchWith (supportsRev, kind, addArgs) source = do- unless ((sourceRevision source /= "") || isNothing (sourceHash source) || not supportsRev) $- liftIO (hPutStrLn stderr "** need a revision for VCS when the hash is given. skipping.") >> mzero-- MaybeT $ liftIO $ do- envs <- getEnvironment- (Nothing, Just stdoutH, _, processH) <- createProcess (proc script args)- { env = Just $ ("PRINT_PATH", "1") : envs- , std_in = Inherit- , std_err = Inherit- , std_out = CreatePipe- }-- exitCode <- waitForProcess processH- case exitCode of- ExitSuccess -> fmap Just . processOutputSwitch . lines =<< hGetContents stdoutH- ExitFailure _ -> return Nothing-- where-- script :: String- script = "nix-prefetch-" ++ kind-- args :: [String]- args = addArgs ++ sourceUrl source : [ sourceRevision source | supportsRev ] ++ maybeToList (sourceHash source)-- processOutputWithRev :: [String] -> IO (DerivationSource, FilePath)- processOutputWithRev [rev,hash,path] = return (DerivationSource kind (sourceUrl source) (extractRevision rev) hash, path)- processOutputWithRev out = unexpectedOutput out-- extractRevision :: String -> String- extractRevision = unwords . drop 3 . words -- drop the "<vcs> revision is" prefix-- processOutput :: [String] -> IO (DerivationSource, FilePath)- processOutput [hash,path] = return (DerivationSource kind (sourceUrl source) (sourceRevision source) hash, path)- processOutput out = unexpectedOutput out-- unexpectedOutput :: [String] -> IO a- unexpectedOutput out = do- hPutStrLn stderr $ "*** unexpected output from " ++ "nix-prefetch-" ++ kind ++ " script: "- hPutStr stderr $ unlines out- exitFailure-- processOutputSwitch :: [String] -> IO (DerivationSource, FilePath)- processOutputSwitch- | supportsRev && isNothing (sourceHash source) = processOutputWithRev- | otherwise = processOutput--stripPrefix :: Eq a => [a] -> [a] -> [a]-stripPrefix prefix as- | prefix' == prefix = stripped- | otherwise = as- where- (prefix', stripped) = splitAt (length prefix) as
− src/Distribution/NixOS/PrettyPrinting.hs
@@ -1,56 +0,0 @@-{- |- Module : Distribution.NixOS.PrettyPrinting- License : BSD3-- Maintainer : nix-dev@cs.uu.nl- Stability : provisional- Portability : portable-- Internal pretty-printing helpers for Nix expressions.--}--module Distribution.NixOS.PrettyPrinting- ( onlyIf- , listattr- , boolattr- , attr- , string- , funargs- , module Text.PrettyPrint- )- where--import Text.PrettyPrint--attr :: String -> Doc -> Doc-attr n v = text n <+> equals <+> v <> semi--onlyIf :: [a] -> Doc -> Doc-onlyIf p d = if not (null p) then d else empty--boolattr :: String -> Bool -> Bool -> Doc-boolattr n p v = if p then attr n (bool v) else empty--listattr :: String -> Doc -> [String] -> Doc-listattr n prefix vs = onlyIf vs $- sep [ text n <+> equals <+> prefix <+> lbrack,- nest 2 $ fsep $ map text vs,- rbrack <> semi- ]--bool :: Bool -> Doc-bool True = text "true"-bool False = text "false"--string :: String -> Doc-string = doubleQuotes . text--prepunctuate :: Doc -> [Doc] -> [Doc]-prepunctuate _ [] = []-prepunctuate p (d:ds) = d : map (p <>) ds--funargs :: [Doc] -> Doc-funargs xs = sep [- lbrace <+> fcat (prepunctuate (comma <> text " ") $ map (nest 2) xs),- rbrace <> colon- ]
− src/Distribution/NixOS/Regex.hs
@@ -1,25 +0,0 @@-{-# LANGUAGE PatternGuards, CPP #-}-{- |- Module : Distribution.NixOS.Derivation.Cabal- License : BSD3-- Maintainer : nix-dev@cs.uu.nl- Stability : provisional- Portability : PatternGuards-- A represtation of Nix expressions based on Cabal builder defined in- @pkgs\/development\/libraries\/haskell\/cabal\/cabal.nix@.--}--module Distribution.NixOS.Regex- ( module Text.Regex.Posix- , regsubmatch- )- where--import Text.Regex.Posix--regsubmatch :: String -> String -> [String]-regsubmatch buf patt = let (_,_,_,x) = f in x- where f :: (String,String,String,[String])- f = match (makeRegexOpts compExtended execBlank patt) buf
+ src/Distribution/Nixpkgs/Fetch.hs view
@@ -0,0 +1,155 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE DeriveGeneric #-}++module Distribution.Nixpkgs.Fetch+ ( Source(..)+ , Hash(..)+ , DerivationSource(..), fromDerivationSource+ , fetch+ , fetchWith+ ) where++import Control.Applicative+import Control.DeepSeq+import Control.Monad+import Control.Monad.IO.Class+import Control.Monad.Trans.Maybe+import Data.Aeson+import qualified Data.ByteString.Lazy.Char8 as BS+import GHC.Generics ( Generic )+import System.Directory+import System.Environment+import System.Exit+import System.IO+import System.Process++-- | A source is a location from which we can fetch, such as a HTTP URL, a GIT URL, ....+data Source = Source+ { sourceUrl :: String -- ^ URL to fetch from.+ , sourceRevision :: String -- ^ Revision to use. For protocols where this doesn't make sense (such as HTTP), this+ -- should be the empty string.+ , sourceHash :: Hash -- ^ The expected hash of the source, if available.+ } deriving (Show, Eq, Ord, Generic)++instance NFData Source++data Hash = Certain String | Guess String | UnknownHash+ deriving (Show, Eq, Ord, Generic)++instance NFData Hash++isUnknown :: Hash -> Bool+isUnknown UnknownHash = True+isUnknown _ = False++hashToList :: Hash -> [String]+hashToList (Certain s) = [s]+hashToList _ = []++-- | A source for a derivation. It always needs a hash and also has a protocol attached to it (url, git, svn, ...).+-- A @DerivationSource@ also always has it's revision fully resolved (not relative revisions like @master@, @HEAD@, etc).+data DerivationSource = DerivationSource+ { derivKind :: String -- ^ The kind of the source. The name of the build-support fetch derivation should be fetch<kind>.+ , derivUrl :: String -- ^ URL to fetch from.+ , derivRevision :: String -- ^ Revision to use. Leave empty if the fetcher doesn't support revisions.+ , derivHash :: String -- ^ The hash of the source.+ }+ deriving (Show, Eq, Ord, Generic)++instance NFData DerivationSource++instance FromJSON DerivationSource where+ parseJSON (Object o) = DerivationSource (error "undefined DerivationSource.kind")+ <$> o .: "url"+ <*> o .: "rev"+ <*> o .: "sha256"+ parseJSON _ = error "invalid DerivationSource"++fromDerivationSource :: DerivationSource -> Source+fromDerivationSource DerivationSource{..} = Source derivUrl derivRevision $ Certain derivHash++-- | Fetch a source, trying any of the various nix-prefetch-* scripts.+fetch :: forall a. (String -> MaybeT IO a) -- ^ This function is passed the output path name as an argument.+ -- It should return 'Nothing' if the file doesn't match the expected format.+ -- This is required, because we cannot always check if a download succeeded otherwise.+ -> Source -- ^ The source to fetch from.+ -> IO (Maybe (DerivationSource, a)) -- ^ The derivation source and the result of the processing function. Returns Nothing if the download failed.+fetch f = runMaybeT . fetchers where+ fetchers :: Source -> MaybeT IO (DerivationSource, a)+ fetchers source = msum . (fetchLocal source :) $ map (\fetcher -> fetchWith fetcher source >>= process)+ [ (False, "zip", [])+ , (False, "url", [])+ , (True, "git", ["--fetch-submodules"])+ , (True, "hg", [])+ , (True, "svn", [])+ , (True, "bzr", [])+ ]++ -- | Remove '/' from the end of the path. Nix doesn't accept paths that+ -- end in a slash.+ stripSlashSuffix :: String -> String+ stripSlashSuffix = reverse . dropWhile (== '/') . reverse++ fetchLocal :: Source -> MaybeT IO (DerivationSource, a)+ fetchLocal src = do+ let path = stripSlashSuffix $ stripPrefix "file://" $ sourceUrl src+ existsFile <- liftIO $ doesFileExist path+ existsDir <- liftIO $ doesDirectoryExist path+ guard $ existsDir || existsFile+ let path' | '/' `elem` path = path+ | otherwise = "./" ++ path+ process (DerivationSource "" path' "" "", path') <|> localArchive path'++ localArchive :: FilePath -> MaybeT IO (DerivationSource, a)+ localArchive path = do+ absolutePath <- liftIO $ canonicalizePath path+ unpacked <- snd <$> fetchWith (False, "zip", []) (Source ("file://" ++ absolutePath) "" UnknownHash)+ process (DerivationSource "" absolutePath "" "", unpacked)++ process :: (DerivationSource, FilePath) -> MaybeT IO (DerivationSource, a)+ process (derivSource, file) = (,) derivSource <$> f file++-- | Like 'fetch', but allows to specify which script to use.+fetchWith :: (Bool, String, [String]) -> Source -> MaybeT IO (DerivationSource, FilePath)+fetchWith (supportsRev, kind, addArgs) source = do+ unless ((sourceRevision source /= "") || isUnknown (sourceHash source) || not supportsRev) $+ liftIO (hPutStrLn stderr "** need a revision for VCS when the hash is given. skipping.") >> mzero++ MaybeT $ liftIO $ do+ envs <- getEnvironment+ (Nothing, Just stdoutH, _, processH) <- createProcess (proc script args)+ { env = Just $ ("PRINT_PATH", "1") : envs+ , std_in = Inherit+ , std_err = Inherit+ , std_out = CreatePipe+ }++ exitCode <- waitForProcess processH+ case exitCode of+ ExitFailure _ -> return Nothing+ ExitSuccess -> do+ buf <- BS.hGetContents stdoutH+ let (l:ls) = reverse (BS.lines buf)+ buf' = BS.unlines (reverse ls)+ case length ls of+ 0 -> return Nothing+ 1 -> return (Just (DerivationSource kind (sourceUrl source) "" (BS.unpack (head ls)) , sourceUrl source))+ _ -> case eitherDecode buf' of+ Left err -> error ("invalid JSON: " ++ err ++ " in " ++ show buf')+ Right ds -> return (Just (ds { derivKind = kind }, BS.unpack l))+ where++ script :: String+ script = "nix-prefetch-" ++ kind++ args :: [String]+ args = addArgs ++ sourceUrl source : [ sourceRevision source | supportsRev ] ++ hashToList (sourceHash source)++stripPrefix :: Eq a => [a] -> [a] -> [a]+stripPrefix prefix as+ | prefix' == prefix = stripped+ | otherwise = as+ where+ (prefix', stripped) = splitAt (length prefix) as
+ src/Distribution/Nixpkgs/Haskell.hs view
@@ -0,0 +1,8 @@+module Distribution.Nixpkgs.Haskell+ ( module Distribution.Nixpkgs.Haskell.BuildInfo+ , module Distribution.Nixpkgs.Haskell.Derivation+ )+ where++import Distribution.Nixpkgs.Haskell.BuildInfo+import Distribution.Nixpkgs.Haskell.Derivation
+ src/Distribution/Nixpkgs/Haskell/BuildInfo.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TemplateHaskell #-}++module Distribution.Nixpkgs.Haskell.BuildInfo+ ( BuildInfo+ , haskell, pkgconfig, system, tool, pPrintBuildInfo+ )+ where++import Control.DeepSeq+import Control.Lens+import Data.Set ( Set )+import Data.Set.Lens+import GHC.Generics ( Generic )+import Language.Nix+import Language.Nix.PrettyPrinting++data BuildInfo = BuildInfo+ { _haskell :: Set Binding+ , _pkgconfig :: Set Binding+ , _system :: Set Binding+ , _tool :: Set Binding+ }+ deriving (Show, Eq, Generic)++makeLenses ''BuildInfo++instance Each BuildInfo BuildInfo (Set Binding) (Set Binding) where+ each f (BuildInfo a b c d) = BuildInfo <$> f a <*> f b <*> f c <*> f d++instance Monoid BuildInfo where+ mempty = BuildInfo mempty mempty mempty mempty+ BuildInfo w1 x1 y1 z1 `mappend` BuildInfo w2 x2 y2 z2 = BuildInfo (w1 `mappend` w2) (x1 `mappend` x2) (y1 `mappend` y2) (z1 `mappend` z2)++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)+ ]
+ src/Distribution/Nixpkgs/Haskell/Constraint.hs view
@@ -0,0 +1,15 @@+module Distribution.Nixpkgs.Haskell.Constraint+ ( Constraint, satisfiesConstraint, satisfiesConstraints+ ) where++import Distribution.Package+import Distribution.Version+import Distribution.Nixpkgs.Haskell.OrphanInstances ( )++type Constraint = Dependency++satisfiesConstraint :: PackageIdentifier -> Constraint -> Bool+satisfiesConstraint (PackageIdentifier pn v) (Dependency cn vr) = (pn /= cn) || (v `withinRange` vr)++satisfiesConstraints :: PackageIdentifier -> [Constraint] -> Bool+satisfiesConstraints p = all (satisfiesConstraint p)
+ src/Distribution/Nixpkgs/Haskell/Derivation.hs view
@@ -0,0 +1,148 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}++module Distribution.Nixpkgs.Haskell.Derivation+ ( Derivation, nullDerivation, pkgid, revision, src, isLibrary, isExecutable+ , extraFunctionArgs, libraryDepends, executableDepends, testDepends, configureFlags+ , cabalFlags, runHaddock, jailbreak, doCheck, testTarget, hyperlinkSource, enableSplitObjs+ , enableLibraryProfiling, enableExecutableProfiling, phaseOverrides, editedCabalFile, metaSection+ , dependencies, setupDepends+ )+ where++import Control.DeepSeq+import Control.Lens+import Data.List+import Data.Set ( Set )+import qualified Data.Set as Set+import Data.Set.Lens+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, FlagName(..) )+import GHC.Generics ( Generic )+import Language.Nix+import Language.Nix.PrettyPrinting++-- | A represtation of Nix expressions for building Haskell packages.+-- The data type correspond closely to the definition of+-- 'PackageDescription' from Cabal.++data Derivation = MkDerivation+ { _pkgid :: PackageIdentifier+ , _revision :: Int+ , _src :: DerivationSource+ , _isLibrary :: Bool+ , _isExecutable :: Bool+ , _extraFunctionArgs :: Set Identifier+ , _setupDepends :: BuildInfo+ , _libraryDepends :: BuildInfo+ , _executableDepends :: BuildInfo+ , _testDepends :: BuildInfo+ , _configureFlags :: Set String+ , _cabalFlags :: FlagAssignment+ , _runHaddock :: Bool+ , _jailbreak :: Bool+ , _doCheck :: Bool+ , _testTarget :: String+ , _hyperlinkSource :: Bool+ , _enableLibraryProfiling :: Bool+ , _enableExecutableProfiling :: Bool+ , _enableSplitObjs :: Bool+ , _phaseOverrides :: String+ , _editedCabalFile :: String+ , _metaSection :: Meta+ }+ deriving (Show, Eq, Generic)++nullDerivation :: Derivation+nullDerivation = MkDerivation+ { _pkgid = error "undefined Derivation.pkgid"+ , _revision = error "undefined Derivation.revision"+ , _src = error "undefined Derivation.src"+ , _isLibrary = error "undefined Derivation.isLibrary"+ , _isExecutable = error "undefined Derivation.isExecutable"+ , _extraFunctionArgs = error "undefined Derivation.extraFunctionArgs"+ , _setupDepends = error "undefined Derivation.setupDepends"+ , _libraryDepends = error "undefined Derivation.libraryDepends"+ , _executableDepends = error "undefined Derivation.executableDepends"+ , _testDepends = error "undefined Derivation.testDepends"+ , _configureFlags = error "undefined Derivation.configureFlags"+ , _cabalFlags = error "undefined Derivation.cabalFlags"+ , _runHaddock = error "undefined Derivation.runHaddock"+ , _jailbreak = error "undefined Derivation.jailbreak"+ , _doCheck = error "undefined Derivation.doCheck"+ , _testTarget = error "undefined Derivation.testTarget"+ , _hyperlinkSource = error "undefined Derivation.hyperlinkSource"+ , _enableLibraryProfiling = error "undefined Derivation.enableLibraryProfiling"+ , _enableExecutableProfiling = error "undefined Derivation.enableExecutableProfiling"+ , _enableSplitObjs = error "undefined Derivation.enableSplitObjs"+ , _phaseOverrides = error "undefined Derivation.phaseOverrides"+ , _editedCabalFile = error "undefined Derivation.editedCabalFile"+ , _metaSection = error "undefined Derivation.metaSection"+ }++makeLenses ''Derivation++makeLensesFor [("_setupDepends", "dependencies"), ("_libraryDepends", "dependencies"), ("_executableDepends", "dependencies"), ("_testDepends", "dependencies")] ''Derivation++instance Package Derivation where+ packageId = view pkgid++instance NFData Derivation++instance Pretty Derivation where+ pPrint drv@(MkDerivation {..}) = funargs (map text ("mkDerivation" : toAscList inputs)) $$ vcat+ [ text "mkDerivation" <+> lbrace+ , nest 2 $ vcat+ [ attr "pname" $ doubleQuotes $ disp (packageName _pkgid)+ , attr "version" $ doubleQuotes $ disp (packageVersion _pkgid)+ , sourceAttr _src+ , onlyIf (_revision > 0) $ attr "revision" $ doubleQuotes $ int _revision+ , onlyIf (not (null _editedCabalFile) && _revision > 0) $ attr "editedCabalFile" $ string _editedCabalFile+ , listattr "configureFlags" empty (map (show . show) renderedFlags)+ , boolattr "isLibrary" (not _isLibrary || _isExecutable) _isLibrary+ , boolattr "isExecutable" (not _isLibrary || _isExecutable) _isExecutable+ , onlyIf (_setupDepends /= mempty) $ pPrintBuildInfo "setup" _setupDepends+ , onlyIf (_libraryDepends /= mempty) $ pPrintBuildInfo "library" _libraryDepends+ , onlyIf (_executableDepends /= mempty) $ pPrintBuildInfo "executable" _executableDepends+ , onlyIf (_testDepends /= mempty) $ pPrintBuildInfo "test" _testDepends+ , boolattr "enableLibraryProfiling" _enableLibraryProfiling _enableLibraryProfiling+ , boolattr "enableExecutableProfiling" _enableExecutableProfiling _enableExecutableProfiling+ , boolattr "enableSplitObjs" (not _enableSplitObjs) _enableSplitObjs+ , boolattr "doHaddock" (not _runHaddock) _runHaddock+ , boolattr "jailbreak" _jailbreak _jailbreak+ , boolattr "doCheck" (not _doCheck) _doCheck+ , onlyIf (not (null _testTarget)) $ attr "testTarget" $ string _testTarget+ , boolattr "hyperlinkSource" (not _hyperlinkSource) _hyperlinkSource+ , onlyIf (not (null _phaseOverrides)) $ vcat ((map text . lines) _phaseOverrides)+ , pPrint _metaSection+ ]+ , rbrace+ ]+ where+ inputs :: Set String+ inputs = Set.unions [ Set.map (view ident) _extraFunctionArgs+ , setOf (dependencies . each . folded . localName . ident) drv+ , Set.fromList ["fetch" ++ derivKind _src | derivKind _src /= "" && not isHackagePackage]+ ]++ renderedFlags = [ text "-f" <> (if enable then empty else char '-') <> text f | (FlagName f, enable) <- _cabalFlags ]+ ++ map text (toAscList _configureFlags)+ isHackagePackage = "mirror://hackage/" `isPrefixOf` derivUrl _src+ sourceAttr (DerivationSource{..})+ | isHackagePackage = attr "sha256" $ string derivHash+ | derivKind /= "" = vcat+ [ text "src" <+> equals <+> text ("fetch" ++ derivKind) <+> lbrace+ , nest 2 $ vcat+ [ attr "url" $ string derivUrl+ , attr "sha256" $ string derivHash+ , if derivRevision /= "" then attr "rev" (string derivRevision) else empty+ ]+ , rbrace <> semi+ ]+ | otherwise = attr "src" $ text derivUrl
+ src/Distribution/Nixpkgs/Haskell/FromCabal.hs view
@@ -0,0 +1,138 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++module Distribution.Nixpkgs.Haskell.FromCabal+ ( HaskellResolver, NixpkgsResolver+ , fromGenericPackageDescription , fromPackageDescription+ )+ where++import Control.Arrow ( second )+import Control.Lens+import Data.Maybe+import Data.Set ( Set )+import qualified Data.Set as Set+import Distribution.Compiler+import Distribution.Nixpkgs.Haskell+import qualified Distribution.Nixpkgs.Haskell as Nix+import Distribution.Nixpkgs.Haskell.Constraint+import Distribution.Nixpkgs.Haskell.FromCabal.License+import Distribution.Nixpkgs.Haskell.FromCabal.Name+import Distribution.Nixpkgs.Haskell.FromCabal.Normalize+import Distribution.Nixpkgs.Haskell.FromCabal.PostProcess+import qualified Distribution.Nixpkgs.Meta as Nix+import Distribution.Package+import Distribution.PackageDescription+import qualified Distribution.PackageDescription as Cabal+import Distribution.PackageDescription.Configuration+import Distribution.System+import Distribution.Text ( display )+import Distribution.Version+import Language.Nix++type HaskellResolver = Dependency -> Bool+type NixpkgsResolver = Identifier -> Maybe Binding++fromGenericPackageDescription :: HaskellResolver -> NixpkgsResolver -> Platform -> CompilerInfo -> FlagAssignment -> [Constraint] -> GenericPackageDescription -> Derivation+fromGenericPackageDescription haskellResolver nixpkgsResolver arch compiler flags constraints descr'' =+ -- TODO: This logic needs simplification and cleanup. :-(+ case finalize haskellResolver of+ Left _ -> case finalize jailbrokenResolver of+ Left missing -> case finalize (const True) of+ Left missing' -> error $ "finalizePackageDescription complains about missing dependencies \+ \even though we told it that everything exists: " ++ show missing'+ Right (descr_,_) -> fromPackageDescription haskellResolver nixpkgsResolver True missing flags descr_+ Right _ -> fromPackageDescription haskellResolver nixpkgsResolver True [] flags descr+ Right _ -> fromPackageDescription haskellResolver nixpkgsResolver False [] flags descr+ where+ descr :: PackageDescription+ Right (descr,_) = finalize jailbrokenResolver++ -- We have to call the Cabal finalizer several times with different resolver functions, and this+ -- convenience function makes our code shorter.+ finalize :: HaskellResolver -> Either [Dependency] (PackageDescription,FlagAssignment)+ finalize resolver = finalizePackageDescription flags resolver arch compiler constraints descr'++ jailbrokenResolver :: HaskellResolver+ jailbrokenResolver (Dependency pkg _) = haskellResolver (Dependency pkg anyVersion)++ -- A variant of the cabal file that has all test suites enabled to ensure+ -- that their dependencies are recognized by finalizePackageDescription.+ descr' :: GenericPackageDescription+ descr' = descr'' { condTestSuites = flaggedTests }++ flaggedTests :: [(String, CondTree ConfVar [Dependency] TestSuite)]+ flaggedTests = map (second (mapTreeData enableTest)) (condTestSuites descr'')++ enableTest :: TestSuite -> TestSuite+ enableTest t = t { testEnabled = True }++fromPackageDescription :: HaskellResolver -> NixpkgsResolver -> Bool -> [Dependency] -> FlagAssignment -> PackageDescription -> Derivation+fromPackageDescription haskellResolver nixpkgsResolver mismatchedDeps missingDeps flags (PackageDescription {..}) = normalize $ postProcess $ nullDerivation+ & isLibrary .~ isJust library+ & pkgid .~ package+ & revision .~ xrev+ & isLibrary .~ isJust library+ & isExecutable .~ not (null executables)+ & extraFunctionArgs .~ mempty+ & libraryDepends .~ maybe mempty (convertBuildInfo . libBuildInfo) library+ & executableDepends .~ mconcat (map (convertBuildInfo . buildInfo) executables)+ & testDepends .~ mconcat (map (convertBuildInfo . testBuildInfo) testSuites)+ & Nix.setupDepends .~ maybe mempty convertSetupBuildInfo setupBuildInfo+ & configureFlags .~ mempty+ & cabalFlags .~ flags+ & runHaddock .~ maybe True (not . null . exposedModules) library+ & jailbreak .~ (mismatchedDeps || not (null missingDeps))+ & doCheck .~ True+ & testTarget .~ mempty+ & hyperlinkSource .~ True+ & enableSplitObjs .~ True+ & enableLibraryProfiling .~ False+ & enableExecutableProfiling .~ False+ & phaseOverrides .~ mempty+ & editedCabalFile .~ (if xrev > 0+ then fromMaybe (error (display package ++ ": X-Cabal-File-Hash field is missing")) (lookup "X-Cabal-File-Hash" customFieldsPD)+ else "")+ & metaSection .~ ( Nix.nullMeta+ & Nix.homepage .~ homepage+ & Nix.description .~ synopsis+ & Nix.license .~ fromCabalLicense license+ & Nix.platforms .~ Nix.allKnownPlatforms+ & Nix.hydraPlatforms .~ Nix.allKnownPlatforms+ & Nix.maintainers .~ mempty+ & Nix.broken .~ not (null missingDeps)+ )+ where+ xrev = maybe 0 read (lookup "x-revision" customFieldsPD)++ resolveInHackage :: Identifier -> Binding+ resolveInHackage i | (i^.ident) `elem` [ n | (Dependency (PackageName n) _) <- missingDeps ] = bindNull i+ | otherwise = binding # (i, path # ["self",i]) -- TODO: "self" shouldn't be hardcoded.++ goodScopes :: Set [Identifier]+ goodScopes = Set.fromList (map ("pkgs":) [[], ["xorg"], ["xlibs"], ["gnome"], ["gnome3"], ["kde4"]])++ resolveInNixpkgs :: Identifier -> Binding+ resolveInNixpkgs i+ | i `elem` ["clang","lldb","llvm"] = binding # (i, path # ["self","llvmPackages",i]) -- TODO: evil!+ | i `elem` ["gtk2","gtk3"] = binding # (i, path # ["pkgs","gnome2","gtk"])+ | Just p <- nixpkgsResolver i, init (view (reference . path) p) `Set.member` goodScopes = p+ | otherwise = bindNull i++ resolveInHackageThenNixpkgs :: Identifier -> Binding+ resolveInHackageThenNixpkgs i | haskellResolver (Dependency (PackageName (i^.ident)) anyVersion) = resolveInHackage i+ | otherwise = resolveInNixpkgs i++ convertBuildInfo :: Cabal.BuildInfo -> Nix.BuildInfo+ convertBuildInfo Cabal.BuildInfo {..} = mempty+ & haskell .~ Set.fromList [ resolveInHackage (toNixName x) | (Dependency x _) <- targetBuildDepends ]+ & system .~ Set.fromList [ resolveInNixpkgs y | x <- extraLibs, y <- libNixName x ]+ & pkgconfig .~ Set.fromList [ resolveInNixpkgs y | Dependency (PackageName x) _ <- pkgconfigDepends, y <- libNixName x ]+ & tool .~ Set.fromList [ resolveInHackageThenNixpkgs y | Dependency (PackageName x) _ <- buildTools, y <- buildToolNixName x ]++ convertSetupBuildInfo :: Cabal.SetupBuildInfo -> Nix.BuildInfo+ convertSetupBuildInfo bi = mempty+ & haskell .~ Set.fromList [ resolveInHackage (toNixName x) | (Dependency x _) <- Cabal.setupDepends bi ]++bindNull :: Identifier -> Binding+bindNull i = binding # (i, path # ["null"])
+ src/Distribution/Nixpkgs/Haskell/FromCabal/Configuration.hs view
@@ -0,0 +1,101 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveGeneric #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Distribution.Nixpkgs.Haskell.FromCabal.Configuration ( Configuration(..), readConfiguration, assertConsistency ) where++import Control.DeepSeq+import Control.Lens+import Control.Monad+import Data.Map as Map+import Data.Set as Set+import Data.Text as T+import Data.Yaml+import Distribution.Compiler+import Distribution.Nixpkgs.Haskell.Constraint+import Distribution.Package+import Distribution.System+import GHC.Generics ( Generic )+import Language.Nix.Identifier++data Configuration = Configuration+ {+ -- |Target compiler. Used by 'finalizePackageDescription' to choose+ -- appropriate flags and dependencies.+ compilerInfo :: CompilerInfo++ -- |Compiler core packages that are also found on Hackage.+ , corePackages :: Set PackageIdentifier++ -- |These packages replace the latest respective version during+ -- dependency resolution.+ , defaultPackageOverrides :: [Constraint]++ -- |These packages are added to the generated set, but the play no+ -- role during dependency resolution.+ , extraPackages :: [Constraint]++ -- |We know that these packages won't build, so we give them an empty+ -- meta.hydraPlatforms attribute to avoid cluttering our Hydra output with+ -- lots of failure messages.+ , dontDistributePackages :: Map PackageName (Set Platform)++ -- |This information is used by the @hackage2nix@ utility to determine the+ -- 'maintainers' for a given Haskell package.+ , packageMaintainers :: Map Identifier (Set PackageName)+ }+ deriving (Show, Generic)++instance NFData Configuration++instance FromJSON Configuration where+ parseJSON (Object o) = Configuration+ <$> o .:? "compiler" .!= unknownCompilerInfo buildCompilerId NoAbiTag+ <*> o .:? "core-packages" .!= mempty+ <*> o .:? "default-package-overrides" .!= mempty+ <*> o .:? "extra-packages" .!= mempty+ <*> o .:? "dont-distribute-packages" .!= mempty+ <*> o .:? "package-maintainers" .!= mempty+ parseJSON _ = error "invalid Configuration"++instance FromJSON Identifier where+ parseJSON (String s) = pure (review ident (T.unpack s))+ parseJSON s = fail ("parseJSON: " ++ show s ++ " is not a valid Nix identifier")++-- aeson-0.11 introduces a general instance, so we just need a couple+-- of specific ones+#if MIN_VERSION_aeson(0,11,0)+instance (FromJSON v) => FromJSON (Map Identifier v) where+ parseJSON = fmap (Map.mapKeys parseKey) . parseJSON++instance (FromJSON v) => FromJSON (Map PackageName v) where+ parseJSON = fmap (Map.mapKeys parseKey) . parseJSON++parseKey :: (FromJSON k) => Text -> k+parseKey s = either error id (parseEither parseJSON (String s))+#else+instance (Ord k, FromJSON k, FromJSON v) => FromJSON (Map k v) where+ parseJSON = fmap (Map.mapKeys parseKey) . parseJSON+ where+ parseKey :: FromJSON k => Text -> k+ parseKey s = either error id (parseEither parseJSON (String s))+#endif++readConfiguration :: FilePath -> IO Configuration+readConfiguration path =+ decodeFile path >>= maybe (fail ("invalid config file at " ++ show path)) assertConsistency++assertConsistency :: Monad m => Configuration -> m Configuration+assertConsistency cfg@(Configuration {..}) = do+ let report msg = fail ("*** configuration error: " ++ msg)++ maintainedPackages = Set.unions (Map.elems packageMaintainers)+ disabledPackages = Map.keysSet dontDistributePackages+ disabledMaintainedPackages = maintainedPackages `Set.intersection` disabledPackages+ unless (Set.null disabledMaintainedPackages) $+ report ("disabled packages that have a maintainer: " ++ show disabledMaintainedPackages)++ return cfg
+ src/Distribution/Nixpkgs/Haskell/FromCabal/Flags.hs view
@@ -0,0 +1,57 @@+module Distribution.Nixpkgs.Haskell.FromCabal.Flags ( configureCabalFlags ) where++import Distribution.Package+import Distribution.PackageDescription+import Data.Version++configureCabalFlags :: PackageIdentifier -> FlagAssignment+configureCabalFlags (PackageIdentifier (PackageName name) version)+ | name == "accelerate-examples"= [disable "opencl"]+ | name == "arithmoi" = [disable "llvm"]+ | name == "darcs" = [enable "library", enable "force-char8-encoding"]+ | name == "diagrams-builder" = [enable "cairo", enable "svg", enable "ps", enable "rasterific"]+ | name == "folds" = [disable "test-hlint"]+ | name == "git-annex" = [ enable "assistant"+ , enable "cryptonite"+ , enable "dbus"+ , enable "desktopnotify"+ , enable "dns"+ , enable "feed"+ , enable "inotify"+ , enable "pairing"+ , enable "production"+ , enable "quvi"+ , enable "s3"+ , enable "tahoe"+ , enable "tdfa"+ , enable "testsuite"+ , enable "torrentparser"+ , enable "webapp"+ , enable "webapp-secure"+ , enable "webdav"+ , enable "xmpp"+ ]+ | name == "haskeline" = [enable "terminfo"]+ | name == "haste-compiler" = [enable "portable"]+ | name == "highlighting-kate" = [enable "pcre-light"]+ | name == "hlibsass" && version >= Version [0,1,5] []+ = [enable "externalLibsass"]+ | name == "hmatrix" = [enable "openblas"]+ | name == "hslua" = [enable "system-lua"]+ | name == "idris" = [enable "gmp", enable "ffi", enable "curses"]+ | name == "io-streams" = [enable "NoInteractiveTests"]+ | name == "liquid-fixpoint" = [enable "build-external"]+ | name == "pandoc" = [enable "https", disable "trypandoc"]+ | name == "reactive-banana-wx" = [disable "buildExamples"]+ | name == "snap-server" = [enable "openssl"]+ | name == "xmobar" = [enable "all_extensions"]+ | name == "xmonad-extras" = [disable "with_hlist", enable "with_split", enable "with_parsec"]+ | name == "yaml" = [enable "system-libyaml"]+ | name == "yi" = [enable "pango", enable "vty"]+ | otherwise = []++enable :: String -> (FlagName,Bool)+enable name = (FlagName name, True)++disable :: String -> (FlagName,Bool)+disable name = (FlagName name, False)
+ src/Distribution/Nixpkgs/Haskell/FromCabal/License.hs view
@@ -0,0 +1,30 @@+module Distribution.Nixpkgs.Haskell.FromCabal.License ( fromCabalLicense ) where++import Distribution.Nixpkgs.License+import Distribution.License ( License(..) )+import Data.Version++fromCabalLicense :: Distribution.License.License -> Distribution.Nixpkgs.License.License+fromCabalLicense (GPL Nothing) = Unknown (Just "GPL")+fromCabalLicense (GPL (Just (Version [2] []))) = Known "stdenv.lib.licenses.gpl2"+fromCabalLicense (GPL (Just (Version [3] []))) = Known "stdenv.lib.licenses.gpl3"+fromCabalLicense (LGPL Nothing) = Unknown (Just "LGPL")+fromCabalLicense (LGPL (Just (Version [2,1] []))) = Known "stdenv.lib.licenses.lgpl21"+fromCabalLicense (LGPL (Just (Version [2] []))) = Known "stdenv.lib.licenses.lgpl2"+fromCabalLicense (LGPL (Just (Version [3] []))) = Known "stdenv.lib.licenses.lgpl3"+fromCabalLicense (AGPL Nothing) = Unknown (Just "AGPL")+fromCabalLicense (AGPL (Just (Version [3] []))) = Known "stdenv.lib.licenses.agpl3"+fromCabalLicense (AGPL (Just (Version [3,0] []))) = Known "stdenv.lib.licenses.agpl3"+fromCabalLicense (MPL (Version [2,0] [])) = Known "stdenv.lib.licenses.mpl20"+fromCabalLicense BSD2 = Known "stdenv.lib.licenses.bsd2"+fromCabalLicense BSD3 = Known "stdenv.lib.licenses.bsd3"+fromCabalLicense BSD4 = Known "stdenv.lib.licenses.bsdOriginal"+fromCabalLicense MIT = Known "stdenv.lib.licenses.mit"+fromCabalLicense PublicDomain = Known "stdenv.lib.licenses.publicDomain"+fromCabalLicense UnspecifiedLicense = Known "stdenv.lib.licenses.unfree"+fromCabalLicense AllRightsReserved = Known "stdenv.lib.licenses.unfree"+fromCabalLicense (Apache Nothing) = Known "stdenv.lib.licenses.asl20"+fromCabalLicense (Apache (Just (Version [2,0] []))) = Known "stdenv.lib.licenses.asl20"+fromCabalLicense ISC = Known "stdenv.lib.licenses.isc"+fromCabalLicense OtherLicense = Unknown Nothing+fromCabalLicense l = error $ "Distribution.Nixpkgs.Haskell.FromCabal.License.fromCabalLicense: unknown license " ++ show l
+ src/Distribution/Nixpkgs/Haskell/FromCabal/Name.hs view
@@ -0,0 +1,198 @@+{-# LANGUAGE OverloadedStrings #-}++module Distribution.Nixpkgs.Haskell.FromCabal.Name ( toNixName, libNixName, buildToolNixName ) where++import Data.String+import Distribution.Package+import Language.Nix++-- | Map Cabal names to Nix attribute names.+toNixName :: PackageName -> Identifier+toNixName (PackageName "") = error "toNixName: invalid empty package name"+toNixName (PackageName n) = fromString n++-- | Map libraries to Nix packages.+--+-- TODO: This list should not be hard-coded here; it belongs into the Nixpkgs+-- repository.++libNixName :: String -> [Identifier]+libNixName "" = []+libNixName "adns" = return "adns"+libNixName "alsa" = return "alsaLib"+libNixName "alut" = return "freealut"+libNixName "appindicator-0.1" = return "appindicator"+libNixName "appindicator3-0.1" = return "appindicator"+libNixName "asound" = return "alsaLib"+libNixName "awesomium-1.6.5" = return "awesomium"+libNixName "b2" = return "libb2"+libNixName "bz2" = return "bzip2"+libNixName "c++" = [] -- What is that?+libNixName "cairo" = return "cairo"+libNixName "cairo-pdf" = return "cairo"+libNixName "cairo-ps" = return "cairo"+libNixName "cairo-svg" = return "cairo"+libNixName "CEGUIBase-0.7.7" = return "CEGUIBase"+libNixName "CEGUIOgreRenderer-0.7.7" = return "CEGUIOgreRenderer"+libNixName "clutter-1.0" = return "clutter"+libNixName "crypt" = [] -- provided by glibc+libNixName "crypto" = return "openssl"+libNixName "curses" = return "ncurses"+libNixName "dl" = [] -- provided by glibc+libNixName "fftw3" = return "fftw"+libNixName "fftw3f" = return "fftwFloat"+libNixName "gconf" = return "GConf"+libNixName "gconf-2.0" = return "GConf"+libNixName "gdk-2.0" = return "gdk2"+libNixName "gdk-3.0" = return "gdk3"+libNixName "gdk-pixbuf-2.0" = return "gdk_pixbuf"+libNixName "gdk-x11-2.0" = return "gdk_x11"+libNixName "gio-2.0" = return "glib"+libNixName "GL" = return "mesa"+libNixName "glib-2.0" = return "glib"+libNixName "GLU" = ["freeglut","mesa"]+libNixName "glut" = ["freeglut","mesa"]+libNixName "gmime-2.4" = return "gmime"+libNixName "gnome-keyring" = return "gnome_keyring"+libNixName "gnome-keyring-1" = return "gnome_keyring"+libNixName "gnome-vfs-2.0" = return "gnome_vfs"+libNixName "gnome-vfs-module-2.0" = return "gnome_vfs_module"+libNixName "gobject-2.0" = return "glib"+libNixName "gobject-introspection-1.0" = return "gobjectIntrospection"+libNixName "gstreamer-0.10" = return "gstreamer"+libNixName "gstreamer-1.0" = return "gstreamer"+libNixName "gstreamer-audio-0.10" = return "gst_plugins_base"+libNixName "gstreamer-audio-1.0" = return "gst_plugins_base"+libNixName "gstreamer-base-0.10" = return "gst_plugins_base"+libNixName "gstreamer-base-1.0" = return "gst_plugins_base"+libNixName "gstreamer-controller-0.10" = return "gstreamer"+libNixName "gstreamer-dataprotocol-0.10" = return "gstreamer"+libNixName "gstreamer-net-0.10" = return "gst_plugins_base"+libNixName "gstreamer-plugins-base-0.10" = return "gst_plugins_base"+libNixName "gstreamer-video-1.0" = return "gst_plugins_base"+libNixName "gthread-2.0" = return "glib"+libNixName "gtk+-2.0" = return "gtk2"+libNixName "gtk+-3.0" = return "gtk3"+libNixName "gtk-x11-2.0" = return "gtk_x11"+libNixName "gtkglext-1.0" = return "gtkglext"+libNixName "gtksourceview-2.0" = return "gtksourceview"+libNixName "gtksourceview-3.0" = return "gtksourceview"+libNixName "hidapi-libusb" = return "hidapi"+libNixName "icudata" = return "icu"+libNixName "icui18n" = return "icu"+libNixName "icuuc" = return "icu"+libNixName "idn" = return "libidn"+libNixName "IL" = return "libdevil"+libNixName "ImageMagick" = return "imagemagick"+libNixName "Imlib2" = return "imlib2"+libNixName "iw" = return "wirelesstools"+libNixName "jack" = return "libjack2"+libNixName "javascriptcoregtk-3.0" = return "javascriptcoregtk"+libNixName "javascriptcoregtk-4.0" = return "javascriptcoregtk"+libNixName "jpeg" = return "libjpeg"+libNixName "lapack" = return "liblapack"+libNixName "ldap" = return "openldap"+libNixName "libavutil" = return "ffmpeg"+libNixName "libglade-2.0" = return "libglade"+libNixName "libgsasl" = return "gsasl"+libNixName "libpcre" = return "pcre"+libNixName "libR" = return "R"+libNixName "librsvg-2.0" = return "librsvg"+libNixName "libsoup-2.4" = return "libsoup"+libNixName "libsoup-gnome-2.4" = return "libsoup"+libNixName "libsystemd" = return "systemd"+libNixName "libusb-1.0" = return "libusb"+libNixName "libxml-2.0" = return "libxml2"+libNixName "libzip" = return "libzip"+libNixName "libzmq" = return "zeromq"+libNixName "m" = [] -- in stdenv+libNixName "magic" = return "file"+libNixName "MagickWand" = return "imagemagick"+libNixName "mono-2.0" = return "mono"+libNixName "mpi" = return "openmpi"+libNixName "ncursesw" = return "ncurses"+libNixName "netsnmp" = return "net_snmp"+libNixName "notify" = return "libnotify"+libNixName "odbc" = return "unixODBC"+libNixName "openblas" = return "openblasCompat"+libNixName "panelw" = return "ncurses"+libNixName "pangocairo" = return "pango"+libNixName "pcap" = return "libpcap"+libNixName "pfs-1.2" = return "pfstools"+libNixName "png" = return "libpng"+libNixName "poppler-glib" = return "poppler"+libNixName "portaudio-2.0" = return "portaudio"+libNixName "pq" = return "postgresql"+libNixName "pthread" = []+libNixName "pulse-simple" = return "libpulseaudio"+libNixName "python-3.3" = return "python33"+libNixName "python-3.4" = return "python34"+libNixName "Qt5Core" = return "qt5"+libNixName "Qt5Gui" = return "qt5"+libNixName "Qt5Qml" = return "qt5"+libNixName "Qt5Quick" = return "qt5"+libNixName "Qt5Widgets" = return "qt5"+libNixName "rt" = [] -- in glibc+libNixName "rtlsdr" = return "rtl-sdr"+libNixName "ruby1.8" = return "ruby"+libNixName "sane-backends" = return "saneBackends"+libNixName "sass" = return "libsass"+libNixName "sdl2" = return "SDL2"+libNixName "SDL2-2.0" = return "SDL2"+libNixName "sndfile" = return "libsndfile"+libNixName "sodium" = return "libsodium"+libNixName "sqlite3" = return "sqlite"+libNixName "ssl" = return "openssl"+libNixName "stdc++" = [] -- What is that?+libNixName "stdc++.dll" = [] -- What is that?+libNixName "systemd-journal" = return "systemd"+libNixName "taglib_c" = return "taglib"+libNixName "tag_c" = return "taglib"+libNixName "udev" = return "systemd";+libNixName "uuid" = return "libossp_uuid";+libNixName "vte-2.90" = return "vte"+libNixName "vte-2.91" = return "vte"+libNixName "wayland-client" = return "wayland"+libNixName "wayland-cursor" = return "wayland"+libNixName "wayland-egl" = return "mesa"+libNixName "wayland-server" = return "wayland"+libNixName "webkit-1.0" = return "webkit"+libNixName "webkit2gtk-4.0" = return "webkit2gtk"+libNixName "webkit2gtk-web-extension-4.0" = return "webkit2gtk-web-extension"+libNixName "webkitgtk" = return "webkit"+libNixName "webkitgtk-3.0" = return "webkit"+libNixName "X11" = return "libX11"+libNixName "xau" = return "libXau"+libNixName "Xcursor" = return "libXcursor"+libNixName "xerces-c" = return "xercesc"+libNixName "Xext" = return "libXext"+libNixName "xft" = return "libXft"+libNixName "Xi" = return "libXi"+libNixName "Xinerama" = return "libXinerama"+libNixName "xkbcommon" = return "libxkbcommon"+libNixName "xml2" = return "libxml2"+libNixName "Xpm" = return "libXpm"+libNixName "Xrandr" = return "libXrandr"+libNixName "Xrender" = return "libXrender"+libNixName "Xss" = return "libXScrnSaver"+libNixName "Xtst" = return "libXtst"+libNixName "Xxf86vm" = return "libXxf86vm"+libNixName "yaml-0.1" = return "libyaml"+libNixName "z" = return "zlib"+libNixName "zmq" = return "zeromq"+libNixName x = return (fromString x)++-- | Map build tool names to Nix attribute names.+buildToolNixName :: String -> [Identifier]+buildToolNixName "" = return (error "buildToolNixName: invalid empty dependency name")+buildToolNixName "cabal" = return "cabal-install"+buildToolNixName "ghc" = []+buildToolNixName "gtk2hsC2hs" = return "gtk2hs-buildtools"+buildToolNixName "gtk2hsHookGenerator" = return "gtk2hs-buildtools"+buildToolNixName "gtk2hsTypeGen" = return "gtk2hs-buildtools"+buildToolNixName "hsc2hs" = []+buildToolNixName "nix-build" = return "nix"+buildToolNixName "nix-env" = return "nix"+buildToolNixName "nix-instantiate" = return "nix"+buildToolNixName "nix-store" = return "nix"+buildToolNixName x = return (fromString x)
+ src/Distribution/Nixpkgs/Haskell/FromCabal/Normalize.hs view
@@ -0,0 +1,57 @@+module Distribution.Nixpkgs.Haskell.FromCabal.Normalize ( normalize, normalizeCabalFlags ) where++import Control.Lens+import Data.Function+import Data.List+import qualified Data.Set as Set+import Data.String+import Distribution.Nixpkgs.Haskell+import Distribution.Nixpkgs.Meta+import Distribution.Package+import Distribution.PackageDescription ( FlagAssignment, FlagName(..) )+import Distribution.Simple.Utils ( lowercase )+import Language.Nix hiding ( quote )++normalize :: Derivation -> Derivation+normalize drv = drv+ & over libraryDepends (normalizeBuildInfo (packageName drv))+ & over executableDepends (normalizeBuildInfo (packageName drv))+ & over testDepends (normalizeBuildInfo (packageName drv))+ & over metaSection normalizeMeta+ & over cabalFlags normalizeCabalFlags+ & jailbreak %~ (&& (packageName drv /= PackageName "jailbreak-cabal"))++normalizeBuildInfo :: PackageName -> BuildInfo -> BuildInfo+normalizeBuildInfo (PackageName pname) bi = bi+ & haskell %~ Set.filter (\b -> view localName b /= fromString pname)+ & tool %~ Set.filter (\b -> view localName b /= fromString pname)++normalizeMeta :: Meta -> Meta+normalizeMeta meta = meta+ & description %~ normalizeSynopsis+ & platforms %~ Set.intersection allKnownPlatforms+ & hydraPlatforms %~ Set.intersection (meta^.platforms)++normalizeSynopsis :: String -> String+normalizeSynopsis desc+ | null desc = []+ | last desc == '.' && length (filter ('.'==) desc) == 1 = normalizeSynopsis (init desc)+ | otherwise = quote (unwords (words desc))++quote :: String -> String+quote ('\\':c:cs) = '\\' : c : quote cs+quote ('"':cs) = '\\' : '"' : quote cs+quote (c:cs) = c : quote cs+quote [] = []++-- |When a flag is specified multiple times, the first occurrence+-- counts. This is counter-intuitive, IMHO, but it's how cabal does it.+-- Flag names are spelled in all lowercase.+--+-- >>> normalizeCabalFlags [(FlagName "foo", True), (FlagName "FOO", True), (FlagName "Foo", False)]+-- [(FlagName "foo",True)]++normalizeCabalFlags :: FlagAssignment -> FlagAssignment+normalizeCabalFlags flags' = nubBy ((==) `on` fst) (sortBy (compare `on` fst) flags)+ where+ flags = [ (FlagName (lowercase n), b) | (FlagName n, b) <- flags' ]
+ src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs view
@@ -0,0 +1,383 @@+{-# LANGUAGE OverloadedStrings #-}++module Distribution.Nixpkgs.Haskell.FromCabal.PostProcess ( postProcess ) where++import Control.Lens+import Data.List.Split+import Data.Set ( Set )+import qualified Data.Set as Set+import Data.Set.Lens+import Distribution.Nixpkgs.Haskell+import Distribution.Nixpkgs.Meta+import Distribution.Package+import Distribution.System+import Distribution.Text+import Distribution.Version+import Language.Nix++postProcess :: Derivation -> Derivation+postProcess deriv = foldr ($) (fixGtkBuilds deriv) [ f | (Dependency n vr, f) <- hooks, packageName deriv == n, packageVersion deriv `withinRange` vr ]++fixGtkBuilds :: Derivation -> Derivation+fixGtkBuilds drv = drv & dependencies . pkgconfig %~ Set.filter (not . collidesWithHaskellName)+ & dependencies . system %~ Set.filter (not . collidesWithHaskellName)+ & dependencies . tool %~ Set.filter (not . collidesWithHaskellName)+ where+ collidesWithHaskellName :: Binding -> Bool+ collidesWithHaskellName b = view localName b `Set.member` buildDeps++ myName :: Identifier+ myName = ident # n where PackageName n = packageName drv++ buildDeps :: Set Identifier+ buildDeps = Set.delete myName (setOf (dependencies . haskell . folded . localName) drv)++hooks :: [(Dependency, Derivation -> Derivation)]+hooks =+ [ ("Agda < 2.5", set (executableDepends . tool . contains (pkg "emacs")) True . set phaseOverrides agdaPostInstall)+ , ("Agda >= 2.5", set (executableDepends . tool . contains (pkg "emacs")) True . set phaseOverrides agda25PostInstall)+ , ("alex < 3.1.5", set (testDepends . tool . contains (pkg "perl")) True)+ , ("alex", set (executableDepends . tool . contains (bind "self.happy")) True)+ , ("bindings-GLFW", over (libraryDepends . system) (Set.union (Set.fromList [bind "pkgs.xorg.libXext", bind "pkgs.xorg.libXfixes"])))+ , ("bustle", set (libraryDepends . pkgconfig . contains "system-glib = pkgs.glib") True)+ , ("Cabal", set doCheck False) -- test suite doesn't work in Nix+ , ("cabal-helper", set doCheck False) -- https://github.com/DanielG/cabal-helper/issues/17+ , ("cabal-install", set phaseOverrides cabalInstallPostInstall)+ , ("darcs", set phaseOverrides darcsInstallPostInstall . set doCheck False)+ , ("dbus", set doCheck False) -- don't execute tests that try to access the network+ , ("dns", set testTarget "spec") -- don't execute tests that try to access the network+ , ("eventstore", over (metaSection . platforms) (Set.filter (\(Platform arch _) -> arch == X86_64)))+ , ("freenect < 1.2.1", over configureFlags (Set.union (Set.fromList ["--extra-include-dirs=${pkgs.freenect}/include/libfreenect", "--extra-lib-dirs=${pkgs.freenect}/lib"])))+ , ("gf", set phaseOverrides gfPhaseOverrides . set doCheck False)+ , ("gi-cairo", giPhaseOverrides) -- https://github.com/haskell-gi/haskell-gi/issues/36+ , ("gi-gio", giPhaseOverrides) -- https://github.com/haskell-gi/haskell-gi/issues/36+ , ("gi-glib", giPhaseOverrides) -- https://github.com/haskell-gi/haskell-gi/issues/36+ , ("gi-gobject", giPhaseOverrides) -- https://github.com/haskell-gi/haskell-gi/issues/36+ , ("gi-pango", giPhaseOverrides) -- https://github.com/haskell-gi/haskell-gi/issues/36+ , ("gio", set (libraryDepends . pkgconfig . contains "system-glib = pkgs.glib") True)+ , ("git", set doCheck False) -- https://github.com/vincenthz/hit/issues/33+ , ("git-annex", gitAnnexHook)+ , ("github-backup", set (executableDepends . tool . contains (pkg "git")) True)+ , ("GlomeVec", set (libraryDepends . pkgconfig . contains (bind "self.llvmPackages.llvm")) True)+ , ("goatee-gtk", over (metaSection . platforms) (Set.filter (\(Platform _ os) -> os /= OSX)))+ , ("gtk3", gtk3Hook)+ , ("haddock", haddockHook) -- https://github.com/haskell/haddock/issues/511+ , ("hakyll", set (testDepends . tool . contains (pkg "utillinux")) True) -- test suite depends on "rev"+ , ("haskell-src-exts == 1.17.1", set doCheck False) -- test suite fails with ghc 8.0.1+ , ("hfsevents", over (metaSection . platforms) (Set.filter (\(Platform _ os) -> os == OSX)))+ , ("HFuse", set phaseOverrides hfusePreConfigure)+ , ("hlibgit2 >= 0.18.0.14", set (testDepends . tool . contains (pkg "git")) True)+ , ("hmatrix", set phaseOverrides "preConfigure = \"sed -i hmatrix.cabal -e 's@/usr/@/dont/hardcode/paths/@'\";")+ , ("holy-project", set doCheck False) -- attempts to access the network+ , ("hsignal < 0.2.7.4", set phaseOverrides "prePatch = \"rm -v Setup.lhs\";") -- https://github.com/amcphail/hsignal/issues/1+ , ("hslua", over (libraryDepends . each) (replace (pkg "lua") (pkg "lua5_1")))+ , ("http-client", set doCheck False) -- attempts to access the network+ , ("http-client-openssl >= 0.2.0.1", set doCheck False) -- attempts to access the network+ , ("http-client-tls >= 0.2.2", set doCheck False) -- attempts to access the network+ , ("http-conduit", set doCheck False) -- attempts to access the network+ , ("imagemagick", set (libraryDepends . pkgconfig . contains (pkg "imagemagick")) True) -- https://github.com/NixOS/cabal2nix/issues/136+ , ("include-file <= 0.1.0.2", set (libraryDepends . haskell . contains (bind "self.random")) True) -- https://github.com/Daniel-Diaz/include-file/issues/1+ , ("js-jquery", set doCheck False) -- attempts to access the network+ , ("jsaddle", set (dependencies . haskell . contains (bind "self.ghcjs-base")) False)+ , ("libconfig", over (libraryDepends . system) (replace "config = null" (pkg "libconfig")))+ , ("liquid-fixpoint", set (executableDepends . system . contains (pkg "ocaml")) True . set (testDepends . system . contains (pkg "z3")) True)+ , ("liquidhaskell", set (testDepends . system . contains (pkg "z3")) True)+ , ("MFlow < 4.6", set (libraryDepends . tool . contains (bind "self.cpphs")) True)+ , ("mwc-random", set doCheck False)+ , ("mysql", set (libraryDepends . system . contains (pkg "mysql")) True)+ , ("network-attoparsec", set doCheck False) -- test suite requires network access+ , ("numeric-qq", set doCheck False) -- test suite doesn't finish even after 1+ days+ , ("pandoc", set jailbreak False) -- jailbreak-cabal break the build+ , ("pandoc >= 1.16.0.2", set doCheck False) -- https://github.com/jgm/pandoc/issues/2709 and https://github.com/fpco/stackage/issues/1332+ , ("pandoc-citeproc", set doCheck False) -- https://github.com/jgm/pandoc-citeproc/issues/172+ , ("readline", over (libraryDepends . system) (Set.union (pkgs ["readline", "ncurses"])))+ , ("rocksdb-haskell", set (metaSection . platforms) (Set.singleton (Platform X86_64 Linux)))+ , ("sdr", over (metaSection . platforms) (Set.filter (\(Platform arch _) -> arch == X86_64))) -- https://github.com/adamwalker/sdr/issues/2+ , ("shake-language-c", set doCheck False) -- https://github.com/samplecount/shake-language-c/issues/26+ , ("sharc-timbre", set (metaSection . broken) True) -- The build takes insanely long, i.e. >8 hours.+ , ("ssh", set doCheck False) -- test suite runs forever, probably can't deal with our lack of network access+ , ("stack", set phaseOverrides stackOverrides . set doCheck False)+ , ("stripe-http-streams", set doCheck False . set (metaSection . broken) False)+ , ("target", set (testDepends . system . contains (pkg "z3")) True)+ , ("terminfo", set (libraryDepends . system . contains (pkg "ncurses")) True)+ , ("text", set doCheck False) -- break infinite recursion+ , ("thyme", set (libraryDepends . tool . contains (bind "self.cpphs")) True) -- required on Darwin+ , ("twilio", set doCheck False) -- attempts to access the network+ , ("tz", set phaseOverrides "preConfigure = \"export TZDIR=${pkgs.tzdata}/share/zoneinfo\";")+ , ("websockets", set doCheck False) -- https://github.com/jaspervdj/websockets/issues/104+ , ("Win32", over (metaSection . platforms) (Set.filter (\(Platform _ os) -> os == Windows)))+ , ("wxc", wxcHook)+ , ("wxcore", set (libraryDepends . pkgconfig . contains (pkg "wxGTK")) True)+ , ("X11", over (libraryDepends . system) (Set.union (Set.fromList $ map bind ["pkgs.xorg.libXinerama","pkgs.xorg.libXext","pkgs.xorg.libXrender"])))+ , ("xmonad", set phaseOverrides xmonadPostInstall)+ , ("zip-archive", over (testDepends . tool) (replace (bind "self.zip") (pkg "zip")))+ ]++pkg :: Identifier -> Binding+pkg i = binding # (i, path # ["pkgs",i])++pkgs :: [Identifier] -> Set Binding+pkgs = Set.fromList . map pkg++bind :: String -> Binding+bind s = binding # (i, path # is)+ where+ is = map (review ident) (splitOn "." s)+ i = last is++replace :: Binding -> Binding -> Set Binding -> Set Binding+replace old new bs = if old `Set.member` bs then Set.insert new (Set.delete old bs) else bs++-- TODO: I need to figure out how to conveniently replace a binding in a set.+gtk3Hook :: Derivation -> Derivation -- https://github.com/NixOS/cabal2nix/issues/145+gtk3Hook = set (libraryDepends . pkgconfig . contains (pkg "gtk3")) True+ . over (libraryDepends . pkgconfig) (Set.filter (\b -> view localName b /= "gtk3"))++haddockHook :: Derivation -> Derivation+haddockHook = set doCheck False+ . set phaseOverrides "preCheck = \"unset GHC_PACKAGE_PATH\";"+ . over (dependencies . haskell) (Set.filter (\b -> view localName b /= "haddock-test"))+ . set (metaSection . broken) False++gitAnnexHook :: Derivation -> Derivation+gitAnnexHook = set phaseOverrides gitAnnexOverrides+ . over (executableDepends . system) (Set.union buildInputs)+ . over (metaSection . platforms) (Set.filter (\(Platform _ os) -> os /= OSX))+ where+ gitAnnexOverrides = unlines+ [ "preConfigure = \"export HOME=$TEMPDIR; patchShebangs .\";"+ , "postBuild = \"ln -sf dist/build/git-annex/git-annex git-annex\";"+ , "installPhase = \"make PREFIX=$out CABAL=./Setup BUILDER=./Setup install\";"+ , "checkPhase = \"./git-annex test\";"+ , "enableSharedExecutables = false;"+ ]+ buildInputs = pkgs ["git","rsync","gnupg","curl","wget","lsof","openssh","which","bup","perl"]++hfusePreConfigure :: String+hfusePreConfigure = unlines+ [ "preConfigure = ''"+ , " sed -i -e \"s@ Extra-Lib-Dirs: /usr/local/lib@ Extra-Lib-Dirs: ${fuse}/lib@\" HFuse.cabal"+ , "'';"+ ]++gfPhaseOverrides :: String+gfPhaseOverrides = unlines+ [ "postPatch = ''"+ , " sed -i \"s|\\\"-s\\\"|\\\"\\\"|\" ./Setup.hs"+ -- Disable silent compilation. Compiling takes long, it is best to see some+ -- output, otherwise it looks like the build step has stalled.+ , " sed -i \"s|numJobs (bf bi)++||\" ./Setup.hs"+ -- Parallel compilation fails. Disable it.+ , "'';"+ , "preBuild = ''export LD_LIBRARY_PATH=`pwd`/dist/build:$LD_LIBRARY_PATH'';"+ -- The build step itself, after having built the library, needs to be able+ -- to find the library it just built in order to compile grammar files.+ ]++wxcHook :: Derivation -> Derivation+wxcHook drv = drv & libraryDepends . system %~ Set.union (Set.fromList [pkg "mesa", bind "pkgs.xorg.libX11"])+ & libraryDepends . pkgconfig . contains (pkg "wxGTK") .~ True+ & phaseOverrides .~ wxcPostInstall (packageVersion drv)+ & runHaddock .~ False+ where+ wxcPostInstall :: Version -> String+ wxcPostInstall version = unlines+ [ "postInstall = \"cp -v dist/build/libwxc.so." ++ display version ++ " $out/lib/libwxc.so\";"+ , "postPatch = \"sed -i -e '/ldconfig inst_lib_dir/d' Setup.hs\";"+ ]++cabalInstallPostInstall :: String+cabalInstallPostInstall = unlines+ [ "postInstall = ''"+ , " mkdir $out/etc"+ , " mv bash-completion $out/etc/bash_completion.d"+ , "'';"+ ]++darcsInstallPostInstall :: String+darcsInstallPostInstall = unlines+ [ "postInstall = ''"+ , " mkdir -p $out/etc/bash_completion.d"+ , " mv contrib/darcs_completion $out/etc/bash_completion.d/darcs"+ , "'';"+ ]++xmonadPostInstall :: String+xmonadPostInstall = unlines+ [ "postInstall = ''"+ , " shopt -s globstar"+ , " mkdir -p $out/share/man/man1"+ , " mv \"$out/\"**\"/man/\"*.1 $out/share/man/man1/"+ , "'';"+ ]++agdaPostInstall :: String+agdaPostInstall = unlines+ [ "postInstall = ''"+ , " $out/bin/agda -c --no-main $(find $out/share -name Primitive.agda)"+ , " $out/bin/agda-mode compile"+ , "'';"+ ]++agda25PostInstall :: String+agda25PostInstall = unlines+ [ "postInstall = ''"+ , " files=(\"$out/share/\"*\"-ghc-\"*\"/Agda-\"*\"/lib/prim/Agda/\"{Primitive.agda,Builtin\"/\"*.agda})"+ -- Separate loops to avoid internal error+ , " for f in \"''${files[@]}\" ; do"+ , " $out/bin/agda $f"+ , " done"+ , " for f in \"''${files[@]}\" ; do"+ , " $out/bin/agda -c --no-main $f"+ , " done"+ , " $out/bin/agda-mode compile"+ , "'';"+ ]++stackOverrides :: String+stackOverrides = unlines+ [ "preCheck = \"export HOME=$TMPDIR\";"+ , "postInstall = ''"+ , " exe=$out/bin/stack"+ , " mkdir -p $out/share/bash-completion/completions"+ , " $exe --bash-completion-script $exe >$out/share/bash-completion/completions/stack"+ , "'';"+ ]++giPhaseOverrides :: Derivation -> Derivation+giPhaseOverrides+ = set phaseOverrides "preConfigure = \"export HASKELL_GI_GIR_SEARCH_PATH=${gobjectIntrospection.dev}/share/gir-1.0\";"+ . set (libraryDepends . pkgconfig . contains (pkg "gobjectIntrospection")) True++{-+postProcess' :: Derivation -> Derivation+postProcess' deriv@(MkDerivation {..})+ | pname == "alex" && version < Version [3,1] []+ = deriv { buildTools = Set.insert "perl" buildTools }+ | pname == "alex" && version >= Version [3,1] []+ = deriv { buildTools = Set.insert "perl" (Set.insert "happy" buildTools) }+ | pname == "apache-md5" = deriv { testDepends = Set.delete "crypto" testDepends }+ | pname == "bits-extras" = deriv { configureFlags = Set.insert "--ghc-option=-lgcc_s" configureFlags+ , extraLibs = Set.filter (/= "gcc_s") extraLibs+ }+ | pname == "Cabal" = deriv { phaseOverrides = "preCheck = \"unset GHC_PACKAGE_PATH; export HOME=$NIX_BUILD_TOP\";" }+ | pname == "cabal-bounds" = deriv { buildTools = Set.insert "cabal-install" buildTools }+ | pname == "editline" = deriv { extraLibs = Set.insert "libedit" extraLibs }+ | pname == "ghc-heap-view" = deriv { phaseOverrides = ghciPostInstall }+ | pname == "ghc-mod" = deriv { phaseOverrides = ghcModPostInstall pname version, buildTools = Set.insert "emacs" buildTools }+ | pname == "ghc-parser" = deriv { buildTools = Set.insert "cpphs" (Set.insert "happy" buildTools)+ , phaseOverrides = ghcParserPatchPhase }+ | pname == "ghc-vis" = deriv { phaseOverrides = ghciPostInstall }+ | pname == "github-backup" = deriv { buildTools = Set.insert "git" buildTools }+ | pname == "gloss-raster" = deriv { extraLibs = Set.insert "llvm" extraLibs }+ | pname == "GLUT" = deriv { extraLibs = Set.fromList ["glut","libSM","libICE","libXmu","libXi","mesa"] `Set.union` extraLibs }+ | pname == "gtkglext" = deriv { pkgConfDeps = Set.insert "pangox_compat" pkgConfDeps }+ | pname == "gtk2hs-buildtools"= deriv { buildDepends = Set.insert "hashtables" buildDepends }+ | pname == "happy" = deriv { buildTools = Set.insert "perl" buildTools }+ | pname == "haskeline" = deriv { buildDepends = Set.insert "utf8-string" buildDepends }+ | pname == "haskell-src" = deriv { buildTools = Set.insert "happy" buildTools }+ | pname == "haskell-src-meta" = deriv { buildDepends = Set.insert "uniplate" buildDepends }+ | pname == "hlibgit2" = deriv { buildTools = Set.insert "git" buildTools }+ | pname == "HList" = deriv { buildTools = Set.insert "diffutils" buildTools }+ | pname == "hmatrix" = deriv { extraLibs = Set.insert "liblapack" (Set.insert "blas" (Set.filter (/= "lapack") extraLibs)) }+ | pname == "hmatrix-special" = deriv { extraLibs = Set.insert "gsl" extraLibs }+ | pname == "idris" = deriv { buildTools = Set.insert "happy" buildTools, extraLibs = Set.insert "gmp" (Set.insert "boehmgc" extraLibs) }+ | pname == "inline-c-cpp" = deriv { testDepends = Set.delete "stdc++" testDepends }+ | pname == "language-c-quote" = deriv { buildTools = Set.insert "alex" (Set.insert "happy" buildTools) }+ | pname == "language-java" = deriv { buildDepends = Set.insert "syb" buildDepends }+ | pname == "lhs2tex" = deriv { extraLibs = Set.insert "texLive" extraLibs, phaseOverrides = lhs2texPostInstall }+ | pname == "libffi" = deriv { extraLibs = Set.delete "ffi" extraLibs }+ | pname == "liquid-fixpoint" = deriv { buildTools = Set.insert "z3" (Set.insert "ocaml" buildTools), configureFlags = Set.insert "-fbuild-external" configureFlags }+ | pname == "liquidhaskell" = deriv { buildTools = Set.insert "z3" buildTools }+ | pname == "multiarg" = deriv { buildDepends = Set.insert "utf8-string" buildDepends }+ | pname == "ncurses" = deriv { phaseOverrides = ncursesPatchPhase }+ | pname == "Omega" = deriv { testDepends = Set.delete "stdc++" testDepends }+ | pname == "OpenAL" = deriv { extraLibs = Set.insert "openal" extraLibs }+ | pname == "OpenGL" = deriv { extraLibs = Set.insert "mesa" (Set.insert "libX11" extraLibs) }+ | pname == "pandoc" = deriv { buildDepends = Set.insert "alex" (Set.insert "happy" buildDepends) }+ | pname == "persistent" = deriv { extraLibs = Set.insert "sqlite3" extraLibs }+ | pname == "purescript" = deriv { buildTools = Set.insert "nodejs" buildTools }+ | pname == "repa-algorithms" = deriv { extraLibs = Set.insert "llvm" extraLibs }+ | pname == "repa-examples" = deriv { extraLibs = Set.insert "llvm" extraLibs }+ | pname == "SDL-image" = deriv { extraLibs = Set.insert "SDL_image" extraLibs }+ | pname == "SDL-mixer" = deriv { extraLibs = Set.insert "SDL_mixer" extraLibs }+ | pname == "SDL-ttf" = deriv { extraLibs = Set.insert "SDL_ttf" extraLibs }+ | pname == "sloane" = deriv { phaseOverrides = sloanePostInstall }+ | pname == "structured-haskell-mode" = deriv { buildTools = Set.insert "emacs" buildTools+ , phaseOverrides = structuredHaskellModePostInstall+ }+ | pname == "target" = deriv { buildTools = Set.insert "z3" buildTools }+ | pname == "threadscope" = deriv { configureFlags = Set.insert "--ghc-options=-rtsopts" configureFlags }+ | pname == "vacuum" = deriv { extraLibs = Set.insert "ghc-paths" extraLibs }+ | pname == "wxcore" = deriv { extraLibs = Set.fromList ["wxGTK","mesa","libX11"] `Set.union` extraLibs }+ | pname == "X11-xft" = deriv { extraLibs = Set.fromList ["pkgconfig","freetype","fontconfig"] `Set.union` extraLibs+ , configureFlags = Set.insert "--extra-include-dirs=${freetype}/include/freetype2" configureFlags+ }+-- Unbreak packages during hackage2nix generation:++ | pname == "hnetcdf" = deriv { testDepends = Set.delete "netcdf" testDepends }+ | pname == "SDL2-ttf" = deriv { buildDepends = Set.delete "SDL2" buildDepends }+ | pname == "hzk" = deriv { testDepends = Set.delete "zookeeper_mt" testDepends, buildTools = Set.insert "zookeeper_mt" buildTools }+ | pname == "z3" = deriv { phaseOverrides = "preBuild = stdenv.lib.optionalString stdenv.isDarwin \"export DYLD_LIBRARY_PATH=${z3}/lib\";" }+ | otherwise = deriv++ghcModPostInstall :: String -> Version -> String+ghcModPostInstall pname version = unlines+ [ "configureFlags = \"--datasubdir=" ++ pname ++ "-" ++ display version ++ "\";"+ , "postInstall = ''"+ , " cd $out/share/" ++ pname ++ "-" ++ display version+ , " make"+ , " rm Makefile"+ , " cd .."+ , " ensureDir \"$out/share/emacs\""+ , " mv " ++ pname ++ "-" ++ display version ++ " emacs/site-lisp"+ , "'';"+ ]++ghciPostInstall :: String+ghciPostInstall = unlines+ [ "postInstall = ''"+ , " ensureDir \"$out/share/ghci\""+ , " ln -s \"$out/share/$pname-$version/ghci\" \"$out/share/ghci/$pname\""+ , "'';"+ ]+++lhs2texPostInstall :: String+lhs2texPostInstall = unlines+ [ "postInstall = ''"+ , " mkdir -p \"$out/share/doc/$name\""+ , " cp doc/Guide2.pdf $out/share/doc/$name"+ , " mkdir -p \"$out/nix-support\""+ , "'';"+ ]++ncursesPatchPhase :: String+ncursesPatchPhase = "patchPhase = \"find . -type f -exec sed -i -e 's|ncursesw/||' {} \\\\;\";"+++structuredHaskellModePostInstall :: String+structuredHaskellModePostInstall = unlines+ [ "postInstall = ''"+ , " emacs -L elisp --batch -f batch-byte-compile \"elisp/\"*.el"+ , " install -d $out/share/emacs/site-lisp"+ , " install \"elisp/\"*.el \"elisp/\"*.elc $out/share/emacs/site-lisp"+ , "'';"+ ]++sloanePostInstall :: String+sloanePostInstall = unlines+ [ "postInstall = ''"+ , " mkdir -p $out/share/man/man1"+ , " cp sloane.1 $out/share/man/man1/"+ , "'';"+ ]++ghcParserPatchPhase :: String+ghcParserPatchPhase = unlines+ [ "patchPhase = ''"+ , " substituteInPlace build-parser.sh --replace \"/bin/bash\" \"$SHELL\""+ , "'';"+ ]++-}
+ src/Distribution/Nixpkgs/Haskell/Hackage.hs view
@@ -0,0 +1,29 @@+module Distribution.Nixpkgs.Haskell.Hackage ( readHashedHackage, module Distribution.Hackage.DB ) where++import Data.ByteString.Lazy ( ByteString )+import Data.Digest.Pure.SHA ( sha256, showDigest )+import Distribution.Hackage.DB+import qualified Distribution.Hackage.DB.Parsed as Unparsed ( parsePackage )+import qualified Distribution.Hackage.DB.Unparsed as Unparsed++-- | A variant of 'readHackage' that adds the SHA256 digest of the+-- original Cabal file to the parsed 'GenericPackageDescription'. That+-- hash is required to build packages with an "edited" cabal file,+-- because Nix needs to download the edited file and patch it into the+-- original tarball.++readHashedHackage :: IO Hackage+readHashedHackage = fmap parseUnparsedHackage Unparsed.readHackage+ where+ parseUnparsedHackage :: Unparsed.Hackage -> Hackage+ parseUnparsedHackage = mapWithKey (mapWithKey . parsePackage)++ parsePackage :: String -> Version -> ByteString -> GenericPackageDescription+ parsePackage name version buf =+ let pkg = Unparsed.parsePackage name version buf+ hash = showDigest (sha256 buf)+ in+ pkg { packageDescription = (packageDescription pkg) {+ customFieldsPD = ("X-Cabal-File-Hash", hash) : customFieldsPD (packageDescription pkg)+ }+ }
+ src/Distribution/Nixpkgs/Haskell/OrphanInstances.hs view
@@ -0,0 +1,116 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Distribution.Nixpkgs.Haskell.OrphanInstances ( ) where++import Control.DeepSeq+import Data.Maybe+import Data.String+import qualified Data.Text as T+import Data.Yaml+import Distribution.Compiler+import Distribution.License+import Distribution.ModuleName hiding ( main, fromString )+import Distribution.Package+import Distribution.PackageDescription+import Distribution.System+import Distribution.Text+import Distribution.Version+import Language.Haskell.Extension++#if !MIN_VERSION_Cabal(1,23,0)+import GHC.Generics ( Generic )+deriving instance Generic (CondTree v c a)+deriving instance Generic (Condition a)+deriving instance Generic ConfVar+deriving instance Generic Flag+deriving instance Generic GenericPackageDescription+#else+instance NFData SetupBuildInfo+#endif++instance (NFData v, NFData c, NFData a) => NFData (CondTree v c a)+instance NFData Arch+instance NFData Benchmark+instance NFData BenchmarkInterface+instance NFData BenchmarkType+instance NFData BuildInfo+instance NFData BuildType+instance NFData CompilerFlavor+instance NFData ConfVar+instance NFData Dependency+instance NFData Executable+instance NFData Extension+instance NFData Flag+instance NFData FlagName+instance NFData GenericPackageDescription+instance NFData KnownExtension+instance NFData Language+instance NFData Library+instance NFData License+instance NFData ModuleName+instance NFData ModuleReexport+instance NFData ModuleRenaming+instance NFData OS+instance NFData PackageDescription+instance NFData RepoKind+instance NFData RepoType+instance NFData SourceRepo+instance NFData TestSuite+instance NFData TestSuiteInterface+instance NFData TestType+instance NFData VersionRange+instance NFData a => NFData (Condition a)+instance NFData Platform+instance NFData CompilerInfo+instance NFData CompilerId+instance NFData AbiTag++instance IsString PackageName where+ fromString = text2isString "PackageName"++instance IsString Version where+ fromString = text2isString "Version"++instance IsString PackageIdentifier where+ fromString = text2isString "PackageIdentifier"++instance IsString Dependency where+ fromString = text2isString "Dependency"++instance IsString CompilerId where+ fromString = text2isString "CompilerId"++instance IsString Platform where+ fromString "i686-linux" = Platform I386 Linux+ fromString "x86_64-linux" = Platform X86_64 Linux+ fromString "x86_64-darwin" = Platform X86_64 OSX+ fromString s = error ("fromString: " ++ show s ++ " is not a valid platform")++instance FromJSON Platform where+ parseJSON (String s) = pure (fromString (T.unpack s))+ parseJSON s = fail ("parseJSON: " ++ show s ++ " is not a valid platform")++instance FromJSON PackageName where+ parseJSON (String s) = return (fromString (T.unpack s))+ parseJSON s = fail ("parseJSON: " ++ show s ++ " is not a valid Haskell package name")++instance FromJSON PackageIdentifier where+ parseJSON (String s) = return (fromString (T.unpack s))+ parseJSON s = fail ("parseJSON: " ++ show s ++ " is not a valid Haskell package identifier")++instance FromJSON Dependency where+ parseJSON (String s) = return (fromString (T.unpack s))+ parseJSON s = fail ("parseJSON: " ++ show s ++ " is not a valid Haskell Dependency")++instance FromJSON CompilerInfo where+ parseJSON (String s) = return (unknownCompilerInfo (fromString (T.unpack s)) NoAbiTag)+ parseJSON s = fail ("parseJSON: " ++ show s ++ " is not a valid Haskell compiler")++-- parsing tools++text2isString :: Text a => String -> String -> a+text2isString t s = fromMaybe (error ("fromString: " ++ show s ++ " is not a valid " ++ t)) (simpleParse s)
+ src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs view
@@ -0,0 +1,157 @@+module Distribution.Nixpkgs.Haskell.PackageSourceSpec+ ( Package(..), getPackage, sourceFromHackage+ ) where++import qualified Control.Exception as Exception+import Control.Monad+import Control.Monad.IO.Class+import Control.Monad.Trans.Maybe+import qualified Data.ByteString.Lazy.Char8 as BS8+import Data.Digest.Pure.SHA ( sha256, showDigest )+import Data.List ( isSuffixOf, isPrefixOf )+import Data.Maybe+import Data.Version+import Distribution.Hackage.DB.Parsed+import Distribution.Nixpkgs.Fetch+import qualified Distribution.Nixpkgs.Haskell.Hackage as DB+import qualified Distribution.Package as Cabal+import Distribution.PackageDescription+import qualified Distribution.PackageDescription as Cabal+import Distribution.Text ( simpleParse )+import System.Directory ( doesDirectoryExist, doesFileExist, createDirectoryIfMissing, getHomeDirectory, getDirectoryContents )+import System.Exit ( exitFailure )+import System.FilePath ( (</>), (<.>) )+import System.IO ( hPutStrLn, stderr, hPutStr )++data Package = Package+ { pkgSource :: DerivationSource+ , pkgCabal :: Cabal.GenericPackageDescription+ }+ deriving (Show)++getPackage :: Maybe String -> Source -> IO Package+getPackage optHackageDB source = do+ (derivSource, pkgDesc) <- fetchOrFromDB optHackageDB source+ flip Package pkgDesc <$> maybe (sourceFromHackage (sourceHash source) $ showPackageIdentifier pkgDesc) return derivSource+++fetchOrFromDB :: Maybe String -> Source -> IO (Maybe DerivationSource, Cabal.GenericPackageDescription)+fetchOrFromDB optHackageDB src+ | "cabal://" `isPrefixOf` sourceUrl src = fmap ((,) Nothing) . fromDB optHackageDB . drop (length "cabal://") $ sourceUrl src+ | otherwise = do+ r <- fetch cabalFromPath src+ case r of+ Nothing ->+ hPutStrLn stderr "*** failed to fetch source. Does the URL exist?" >> exitFailure+ Just (derivSource, (externalSource, pkgDesc)) ->+ return (derivSource <$ guard externalSource, pkgDesc)++fromDB :: Maybe String -> String -> IO Cabal.GenericPackageDescription+fromDB optHackageDB pkg = do+ pkgDesc <- (lookupVersion <=< DB.lookup name) <$> maybe DB.readHashedHackage DB.readHackage' optHackageDB+ case pkgDesc of+ Just r -> return r+ Nothing -> hPutStrLn stderr "*** no such package in the cabal database (did you run cabal update?). " >> exitFailure+ where+ pkgId = fromMaybe (error ("invalid Haskell package id " ++ show pkg)) (simpleParse pkg)+ Cabal.PackageName name = Cabal.pkgName pkgId+ version = Cabal.pkgVersion pkgId++ lookupVersion :: DB.Map DB.Version Cabal.GenericPackageDescription -> Maybe Cabal.GenericPackageDescription+ lookupVersion+ | null (versionBranch version) = fmap snd . listToMaybe . reverse . DB.toAscList+ | otherwise = DB.lookup version+++readFileMay :: String -> IO (Maybe String)+readFileMay file = do+ e <- doesFileExist file+ if e+ then Just <$> readFile file+ else return Nothing++hashCachePath :: String -> IO String+hashCachePath pid = do+ home <- getHomeDirectory+ let cacheDir = home </> ".cache/cabal2nix"+ createDirectoryIfMissing True cacheDir+ return $ cacheDir </> pid <.> "sha256"++sourceFromHackage :: Hash -> String -> IO DerivationSource+sourceFromHackage optHash pkgId = do+ cacheFile <- hashCachePath pkgId+ cachedHash <-+ case optHash of+ Certain h -> return . Certain $ h+ Guess h -> return . Guess $ h+ _ -> fmap (maybe UnknownHash Certain) . readFileMay $ cacheFile+ let url = "mirror://hackage/" ++ pkgId ++ ".tar.gz"++ -- Use the cached hash (either from cache file or given on cmdline via sha256 opt)+ -- if available, otherwise download from hackage to compute hash.+ case cachedHash of+ Guess hash -> return $ DerivationSource "url" url "" hash+ Certain hash ->+ -- We need to force the hash here. If we didn't do this, then when reading the+ -- hash from the cache file, the cache file will still be open for reading+ -- (because lazy io) when writeFile opens the file again for writing. By forcing+ -- the hash here, we ensure that the file is closed before opening it again.+ seq (length hash) $+ DerivationSource "url" url "" hash <$ writeFile cacheFile hash+ UnknownHash -> do+ maybeHash <- runMaybeT (derivHash . fst <$> fetchWith (False, "url", []) (Source url "" UnknownHash))+ case maybeHash of+ Just hash ->+ seq (length hash) $+ DerivationSource "url" url "" hash <$ writeFile cacheFile hash+ Nothing -> do+ hPutStr stderr $ unlines+ [ "*** cannot compute hash. (Not a hackage project?)"+ , " If your project is not on hackage, please supply the path to the root directory of"+ , " the project, not to the cabal file."+ , ""+ , " If your project is on hackage but you still want to specify the hash manually, you"+ , " can use the --sha256 option."+ ]+ exitFailure++showPackageIdentifier :: Cabal.GenericPackageDescription -> String+showPackageIdentifier pkgDesc = name ++ "-" ++ showVersion version where+ pkgId = Cabal.package . Cabal.packageDescription $ pkgDesc+ Cabal.PackageName name = Cabal.packageName pkgId+ version = Cabal.packageVersion pkgId++cabalFromPath :: FilePath -> MaybeT IO (Bool, Cabal.GenericPackageDescription)+cabalFromPath path = do+ d <- liftIO $ doesDirectoryExist path+ (,) d <$> if d+ then cabalFromDirectory path+ else cabalFromFile False path++cabalFromDirectory :: FilePath -> MaybeT IO Cabal.GenericPackageDescription+cabalFromDirectory dir = do+ cabals <- liftIO $ getDirectoryContents dir >>= filterM doesFileExist . map (dir </>) . filter (".cabal" `isSuffixOf`)+ case cabals of+ [cabalFile] -> cabalFromFile True cabalFile+ _ -> liftIO $ hPutStrLn stderr "*** found zero or more than one cabal file. Exiting." >> exitFailure++handleIO :: (Exception.IOException -> IO a) -> IO a -> IO a+handleIO = Exception.handle++cabalFromFile :: Bool -> FilePath -> MaybeT IO Cabal.GenericPackageDescription+cabalFromFile failHard file =+ -- readFile throws an error if it's used on binary files which contain sequences+ -- that do not represent valid characters. To catch that exception, we need to+ -- wrap the whole block in `catchIO`, because of lazy IO. The `case` will force+ -- the reading of the file, so we will always catch the expression here.+ MaybeT $ handleIO (\err -> Nothing <$ hPutStrLn stderr ("*** parsing cabal file: " ++ show err)) $ do+ buf <- BS8.readFile file+ let hash = showDigest (sha256 buf)+ case parsePackage' buf of+ Left msg -> if failHard+ then fail ("*** cannot parse " ++ show file ++ ": " ++ msg)+ else return Nothing+ Right pkg -> do return $ Just $ pkg { packageDescription = (packageDescription pkg) {+ customFieldsPD = ("X-Cabal-File-Hash", hash) : customFieldsPD (packageDescription pkg)+ }+ }
− src/cabal2nix.hs
@@ -1,109 +0,0 @@-module Main ( main ) where--import Cabal2Nix.Generate ( cabal2nix )-import Cabal2Nix.Normalize ( normalize )-import Cabal2Nix.Package-import Cabal2Nix.Version-import Distribution.NixOS.Derivation.Cabal hiding ( version )-import Distribution.NixOS.Fetch--import Control.Exception ( bracket )-import Control.Monad ( when )-import Distribution.Text ( disp )-import System.Console.GetOpt ( OptDescr(..), ArgDescr(..), ArgOrder(..), usageInfo, getOpt )-import System.Environment ( getArgs )-import System.Exit ( exitFailure, exitSuccess )-import System.IO ( hPutStrLn, hFlush, stdout, stderr )--data Configuration = Configuration- { optPrintHelp :: Bool- , optPrintVersion :: Bool- , optSha256 :: Maybe String- , optMaintainer :: [String]- , optPlatform :: [String]- , optHaddock :: Bool- , optDoCheck :: Bool- , optJailbreak :: Bool- , optRevision :: String- , optHyperlinkSource :: Bool- , optHackageDb :: Maybe FilePath- }- deriving (Show)--defaultConfiguration :: Configuration-defaultConfiguration = Configuration- { optPrintHelp = False- , optPrintVersion = False- , optSha256 = Nothing- , optMaintainer = []- , optPlatform = []- , optHaddock = True- , optDoCheck = True- , optJailbreak = False- , optRevision = ""- , optHyperlinkSource = True- , optHackageDb = Nothing- }--options :: [OptDescr (Configuration -> Configuration)]-options =- [ Option "h" ["help"] (NoArg (\o -> o { optPrintHelp = True })) "show this help text"- , Option "v" ["version"] (NoArg (\o -> o { optPrintVersion = True })) "print version"- , Option "" ["hackage-db"] (ReqArg (\x o -> o { optHackageDb = Just x }) "FILEPATH") "path to the local hackage db in tar format"- , Option "" ["sha256"] (ReqArg (\x o -> o { optSha256 = Just x }) "HASH") "sha256 hash of source tarball"- , Option "m" ["maintainer"] (ReqArg (\x o -> o { optMaintainer = x : optMaintainer o }) "MAINTAINER") "maintainer of this package (may be specified multiple times)"- , Option "p" ["platform"] (ReqArg (\x o -> o { optPlatform = x : optPlatform o }) "PLATFORM") "supported build platforms (may be specified multiple times)"- , Option "" ["jailbreak"] (NoArg (\o -> o { optJailbreak = True })) "don't honor version restrictions on build inputs"- , Option "" ["no-haddock"] (NoArg (\o -> o { optHaddock = False })) "don't run Haddock when building this package"- , Option "" ["no-check"] (NoArg (\o -> o { optDoCheck = False })) "don't run regression test suites of this package"- , Option "" ["rev"] (ReqArg (\x o -> o { optRevision = x }) "REVISION") "revision, only used when fetching from VCS"- , Option "" ["no-hyperlink-source"] (NoArg (\o -> o { optHyperlinkSource = False })) "don't add pretty-printed source code to the documentation"- ]--usage :: String-usage = usageInfo "Usage: cabal2nix [options] URI" options ++ unlines- [ ""- , "Recognized URI schemes:"- , ""- , " cabal://pkgname-pkgversion download the specified package from Hackage"- , " cabal://pkgname download latest version of the specified package from Hackage"- , " file:///local/path load the Cabal file from the local disk"- , " /local/path abbreviated version of file URI"- , " <git/svn/bzr/hg URL> download the source from the specified repository"- , ""- , "If the URI refers to a cabal file, information for building the package will be retrieved from that file, but "- , "hackage will be used as a source for the derivation."- , "Otherwise, the supplied URI will be used to as the source for the derivation and the information is taken"- , "from the cabal file at the root of the downloaded source."- ]--cmdlineError :: String -> IO a-cmdlineError "" = hPutStrLn stderr usage >> exitFailure-cmdlineError errMsg = hPutStrLn stderr errMsg >> cmdlineError ""--main :: IO ()-main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() -> do- args' <- getArgs- (cfg,args) <- case getOpt Permute options args' of- (o,n,[] ) -> return (foldl (flip ($)) defaultConfiguration o,n)- (_,_,errs) -> cmdlineError (concatMap ("*** "++) errs)-- when (optPrintHelp cfg) (putStr usage >> exitSuccess)- when (optPrintVersion cfg) (putStrLn version >> exitSuccess)- when (length args /= 1) (cmdlineError "*** exactly one url-to-cabal-file must be specified\n")-- pkg <- getPackage (optHackageDb cfg) $ Source (head args) (optRevision cfg) (optSha256 cfg)-- let deriv = (cabal2nix $ cabal pkg) { src = source pkg- , runHaddock = optHaddock cfg- , jailbreak = optJailbreak cfg- , hyperlinkSource = optHyperlinkSource cfg- }- deriv' = deriv { metaSection = (metaSection deriv)- { maintainers = optMaintainer cfg- , platforms = optPlatform cfg- }- , doCheck = doCheck deriv && optDoCheck cfg- }-- putStr (show (disp (normalize deriv')))
− src/hackage4nix.hs
@@ -1,260 +0,0 @@-module Main ( main ) where--import Cabal2Nix.Generate-import Cabal2Nix.Normalize-import Control.Exception ( bracket )-import Control.Monad.RWS-import Data.List-import qualified Data.Set as Set-import Data.Version-import qualified Distribution.Hackage.DB as DB-import Distribution.NixOS.Derivation.Cabal-import Distribution.Package-import Distribution.PackageDescription ( GenericPackageDescription() )-import Distribution.Text-import System.Console.GetOpt ( OptDescr(..), ArgDescr(..), ArgOrder(..), usageInfo, getOpt )-import System.Directory-import System.Environment-import System.Exit-import System.FilePath-import System.IO-import Text.Regex.Posix--data Pkg = Pkg Derivation FilePath Bool- deriving (Show, Eq, Ord)--type PkgSet = Set.Set Pkg--data Configuration = Configuration- { _msgDebug :: String -> IO ()- , _msgInfo :: String -> IO ()- , _hackageDb :: DB.Hackage- , _force :: Bool- }--defaultConfiguration :: Configuration-defaultConfiguration = Configuration- { _msgDebug = hPutStrLn stderr- , _msgInfo = hPutStrLn stderr- , _hackageDb = DB.empty- , _force = False- }--type Hackage4Nix a = RWST Configuration () PkgSet IO a--io :: (MonadIO m) => IO a -> m a-io = liftIO--readDirectory :: FilePath -> IO [FilePath]-readDirectory dirpath = do- entries <- getDirectoryContents dirpath- return [ x | x <- entries, x /= ".", x /= ".." ]--msgDebug, msgInfo :: String -> Hackage4Nix ()-msgDebug msg = ask >>= \s -> io (_msgDebug s msg)-msgInfo msg = ask >>= \s -> io (_msgInfo s msg)--getCabalPackage :: String -> Version -> Hackage4Nix GenericPackageDescription-getCabalPackage name vers = do- db <- asks _hackageDb- case DB.lookup name db of- Just db' -> case DB.lookup vers db' of- Just pkg -> return pkg- Nothing -> fail ("hackage doesn't know about " ++ name ++ " version " ++ display vers)- Nothing -> fail ("hackage doesn't know about " ++ show name)--discoverNixFiles :: (FilePath -> Hackage4Nix ()) -> FilePath -> Hackage4Nix ()-discoverNixFiles yield dirOrFile = do- isFile <- io (doesFileExist dirOrFile)- case (isFile, takeExtension dirOrFile) of- (True,".nix") -> yield dirOrFile- (True,_) -> return ()- (False,_) -> io (readDirectory dirOrFile) >>= mapM_ (discoverNixFiles yield . (dirOrFile </>))--regenerateDerivation :: Derivation -> String -> Bool-regenerateDerivation _ buf = not (buf =~ "(pre|post)Configure|(pre|post)Install|patchPhase|patches|broken|editedCabalFile")--parseNixFile :: FilePath -> String -> Hackage4Nix (Maybe Pkg)-parseNixFile path buf- | not (buf =~ "cabal.mkDerivation")- = msgDebug ("ignore non-cabal package " ++ path) >> return Nothing- | any (`isSuffixOf`path) badPackagePaths- = msgDebug ("ignore known bad package " ++ path) >> return Nothing- | Just deriv <- parseDerivation buf- = do forceReGen <- asks _force- let reGen = regenerateDerivation deriv buf- return (Just (Pkg deriv path (forceReGen || reGen)))- | otherwise = msgInfo ("failed to parse file " ++ path) >> return Nothing--selectLatestVersions :: PkgSet -> PkgSet-selectLatestVersions = Set.fromList . nubBy f2 . sortBy f1 . Set.toList- where- f1 (Pkg deriv1 _ _) (Pkg deriv2 _ _)- | pname deriv1 == pname deriv2 = compare (version deriv2) (version deriv1)- | otherwise = compare (pname deriv1) (pname deriv2)- f2 (Pkg deriv1 _ _) (Pkg deriv2 _ _) = pname deriv1 == pname deriv2--discoverUpdates :: String -> Version -> Hackage4Nix [Version]-discoverUpdates name vers = do- db <- asks _hackageDb- case DB.lookup name db of- Just pkgs -> return (filter (>vers) (DB.keys pkgs))- Nothing -> fail ("discoverUpdates cannot find package " ++ show name ++ " on Hackage")--updateNixPkgs :: [FilePath] -> Hackage4Nix ()-updateNixPkgs paths = do- -- Traverse the given directorcy structure and discover all available- -- Haskell packages.- forM_ paths $ \fileOrDir -> do- msgDebug $ "scanning " ++ show fileOrDir- flip discoverNixFiles fileOrDir $ \file -> do- nix' <- io (readFile file) >>= parseNixFile file- flip (maybe (return ())) nix' $ \nix ->- modify (Set.insert nix)-- -- Re-generate all Haskell packages in-place (unless- -- 'regenerateDerivation' decided that this particular package- -- shouldn't be touched.- latestVersions <- gets selectLatestVersions- let latestVersionMap :: [(String,Version)]- latestVersionMap = [ (pname deriv, version deriv) | Pkg deriv _ _ <- Set.toList latestVersions ]- let isLatest :: Derivation -> Bool- isLatest deriv = maybe False (version deriv ==) (lookup (pname deriv) latestVersionMap)- get >>= \pkgset -> forM_ (Set.toList pkgset) $ \nix -> do- let Pkg deriv path regenerate = nix- maints = maintainers (metaSection deriv)- plats = platforms (metaSection deriv)- hplats = if isLatest deriv then hydraPlatforms (metaSection deriv) else ["self.stdenv.lib.platforms.none"]-- when regenerate $ do- msgDebug ("re-generate " ++ path)- pkg <- getCabalPackage (pname deriv) (version deriv)- let deriv' = (cabal2nix pkg) { src = src deriv- , runHaddock = runHaddock deriv- , doCheck = doCheck deriv- , jailbreak = jailbreak deriv- , hyperlinkSource = hyperlinkSource deriv- , enableSplitObjs = enableSplitObjs deriv- }- meta = metaSection deriv'- plats' = if null plats then platforms meta else plats- deriv'' = deriv' { metaSection = meta- { maintainers = maints- , platforms = plats'- , hydraPlatforms = hplats- }- }- io $ writeFile path (show (disp (normalize deriv'')))-- -- Discover available updates and print the appropriate cabal2nix- -- command line to the console for the user to execute at his/her- -- discretion.- updates' <- forM (Set.elems latestVersions) $ \pkg -> do- let Pkg deriv _ _ = pkg- updates <- discoverUpdates (pname deriv) (version deriv)- return (pkg,updates)- let updates = [ u | u@(_,_:_) <- updates' ]- unless (null updates) $ do- msgInfo "The following updates are available:"- forM_ updates $ \(pkg,versions) -> do- let Pkg deriv path regenerate = pkg- msgInfo ""- msgInfo $ display (packageId deriv) ++ ":"- forM_ versions $ \newVersion -> do- let deriv' = deriv { version = newVersion }- msgInfo $ " " ++ genCabal2NixCmdline (Pkg deriv' path regenerate)- return ()--genCabal2NixCmdline :: Pkg -> String-genCabal2NixCmdline (Pkg deriv path _) = unwords $ ["cabal2nix"] ++ opts ++ ['>':path']- where- meta = metaSection deriv- opts = [cabal] ++ maints' ++ plats' ++ hplats'- ++ (if jailbreak deriv then ["--jailbreak"] else [])- ++ (if runHaddock deriv then [] else ["--no-haddock"])- ++ (if doCheck deriv then [] else ["--no-check"])- cabal = "cabal://" ++ display (packageId deriv)- maints' = [ "--maintainer=" ++ normalizeMaintainer m | m <- maintainers meta ]- plats'- | ["self.ghc.meta.platforms"] == platforms meta = []- | otherwise = [ "--platform=" ++ p | p <- platforms meta ]- hplats'- | ["self.ghc.meta.platforms"] == platforms meta = []- | otherwise = [ "--hydra-platform=" ++ p | p <- hydraPlatforms meta ]- path'- | path =~ "/[0-9\\.]+\\.nix$" = replaceFileName path (display (version deriv) <.> "nix")- | otherwise = path--normalizeMaintainer :: String -> String-normalizeMaintainer x- | "self.stdenv.lib.maintainers." `isPrefixOf` x = drop 28 x- | otherwise = x--data CliOption = PrintHelp | Verbose | ForceRegen- deriving (Eq)--main :: IO ()-main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() -> do- let options :: [OptDescr CliOption]- options =- [ Option "h" ["help"] (NoArg PrintHelp) "show this help text"- , Option "v" ["verbose"] (NoArg Verbose) "enable noisy debug output"- , Option "" ["force"] (NoArg ForceRegen) "re-generate all files in place"- ]-- usage :: String- usage = usageInfo "Usage: hackage4nix [options] [dir-or-file ...]" options ++ unlines- [ ""- , "The purpose of 'hackage4nix' is to keep all Haskell packages in our"- , "repository packages up-to-date. It scans a checked-out copy of"- , "Nixpkgs for expressions that use 'cabal.mkDerivation', and"- , "re-generates them in-place with cabal2nix."- ]-- cmdlineError :: String -> IO a- cmdlineError "" = hPutStrLn stderr usage >> exitFailure- cmdlineError errMsg = hPutStrLn stderr errMsg >> cmdlineError ""-- args' <- getArgs- (opts,args) <- case getOpt Permute options args' of- (o,n,[] ) -> return (o,n)- (_,_,errs) -> cmdlineError (concatMap (\e -> '*':'*':'*':' ':e) errs)-- when (PrintHelp `elem` opts) (cmdlineError "")-- hackage <- DB.readHackage- let cfg = defaultConfiguration- { _msgDebug = if Verbose `elem` opts then _msgDebug defaultConfiguration else const (return ())- , _hackageDb = hackage- , _force = ForceRegen `elem` opts- }- ((),_,()) <- runRWST (updateNixPkgs args) cfg Set.empty- return ()----- Packages that cabal2nix cannot generate build expressions for.--badPackagePaths :: [FilePath]-badPackagePaths = [ -- These expression are not found on Hackage:- "haskell-platform/2009.2.0.2.nix", "haskell-platform/2010.1.0.0.nix"- , "haskell-platform/2010.2.0.0.nix", "haskell-platform/2011.2.0.0.nix"- , "haskell-platform/2011.2.0.1.nix", "haskell-platform/2011.4.0.0.nix"- , "haskell-platform/2012.2.0.0.nix", "haskell-platform/2012.4.0.0.nix"- , "haskell-platform/2013.2.0.0.nix", "compilers/flapjax/default.nix"- , "pkgs/games/uqm/3dovideo.nix", "haskell/ghcjs-prim/default.nix"- , "system/journal-mailer/default.nix", "development/compilers/ghcjs/default.nix"- -- Our primitive parser cannot handle these files.- , "top-level/all-packages.nix", "top-level/haskell-packages.nix"- -- This build is way too complicated to maintain it automatically.- , "pkgs/development/compilers/pakcs/default.nix"- , "pkgs/development/libraries/haskell/hoogle/local.nix"- -- Not registered on Hackage.- , "pkgs/development/compilers/agda/stdlib.nix"- , "pkgs/development/compilers/cryptol/1.8.x.nix"- , "pkgs/development/compilers/cryptol/2.0.x.nix"- , "pkgs/development/compilers/jhc/default.nix"- , "pkgs/development/tools/haskell/cabal-delete/default.nix"- , "pkgs/tools/networking/sproxy-web/default.nix"- , "pkgs/tools/networking/sproxy/default.nix"- , "pkgs/applications/editors/yi/yi-custom.nix"- ]
− test/doc-test.hs
@@ -1,37 +0,0 @@-{-- Module : Main- Copyright : (c) 2013 Peter Simons- License : BSD3-- Maintainer : simons@cryp.to- Stability : provisional- Portability : portable-- Cabal2nix doctest suite.--}--module Main ( main ) where--import Test.DocTest--main :: IO ()-main = do- let libs = [ "dist/build/autogen/Paths_cabal2nix.hs"- , "src/Cabal2Nix/License.hs"- , "src/Cabal2Nix/CorePackages.hs"- , "src/Cabal2Nix/Flags.hs"- , "src/Cabal2Nix/Generate.hs"- , "src/Cabal2Nix/Name.hs"- , "src/Cabal2Nix/Normalize.hs"- , "src/Cabal2Nix/Package.hs"- , "src/Cabal2Nix/PostProcess.hs"- , "src/Cabal2Nix/Version.hs"- , "src/Distribution/NixOS/Derivation/Cabal.hs"- , "src/Distribution/NixOS/Derivation/License.hs"- , "src/Distribution/NixOS/Derivation/Meta.hs"- , "src/Distribution/NixOS/Fetch.hs"- , "src/Distribution/NixOS/PrettyPrinting.hs"- , "src/Distribution/NixOS/Regex.hs"- ]- doctest $ "src/cabal2nix.hs" : libs- doctest $ "src/hackage4nix.hs" : libs