distribution-nixpkgs (empty) → 1
raw patch · 9 files changed
+420/−0 lines, 9 filesdep +Cabaldep +QuickCheckdep +aesonsetup-changed
Dependencies added: Cabal, QuickCheck, aeson, base, bytestring, containers, deepseq, distribution-nixpkgs, doctest, hspec, language-nix, lens, pretty, process, split
Files
- LICENSE +30/−0
- Setup.lhs +8/−0
- distribution-nixpkgs.cabal +70/−0
- src/Distribution/Nixpkgs/License.hs +48/−0
- src/Distribution/Nixpkgs/Meta.hs +100/−0
- src/Distribution/Nixpkgs/PackageMap.hs +59/−0
- src/Internal/OrphanInstances.hs +11/−0
- src/Language/Nix/PrettyPrinting.hs +62/−0
- test/Main.hs +32/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Redistribution and use in source and binary forms, with or+without modification, are permitted provided that the+following conditions are met:++ * Redistributions of source code must retain the above+ copyright notice, this list of conditions and the+ following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the+ following disclaimer in the documentation and/or other+ materials provided with the distribution.++ * The names of its contributors may not be used to endorse+ or promote products derived from this software without+ specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND+CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.lhs view
@@ -0,0 +1,8 @@+#!/usr/bin/env runhaskell++> module Main (main) where+>+> import Distribution.Simple+>+> main :: IO ()+> main = defaultMain
+ distribution-nixpkgs.cabal view
@@ -0,0 +1,70 @@+-- This file has been generated from package.yaml by hpack version 0.14.0.+--+-- see: https://github.com/sol/hpack++name: distribution-nixpkgs+version: 1+synopsis: Types and functions to manipulate the Nixpkgs distribution.+description: Types and functions to represent, query, and manipulate the Nixpkgs distribution.+category: Distribution+homepage: https://github.com/peti/distribution-nixpkgs#readme+bug-reports: https://github.com/peti/distribution-nixpkgs/issues+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++source-repository head+ type: git+ location: https://github.com/peti/distribution-nixpkgs++library+ hs-source-dirs:+ src+ ghc-options: -Wall+ build-depends:+ aeson+ , base > 4.2 && < 5+ , bytestring+ , Cabal > 1.24+ , containers+ , deepseq >= 1.4+ , language-nix > 2+ , lens+ , pretty >= 1.1.2+ , process+ , split+ exposed-modules:+ Distribution.Nixpkgs.License+ Distribution.Nixpkgs.Meta+ Distribution.Nixpkgs.PackageMap+ Language.Nix.PrettyPrinting+ other-modules:+ Internal.OrphanInstances+ default-language: Haskell2010++test-suite spec+ type: exitcode-stdio-1.0+ main-is: Main.hs+ hs-source-dirs:+ test+ ghc-options: -Wall+ build-depends:+ aeson+ , base > 4.2 && < 5+ , bytestring+ , Cabal > 1.24+ , containers+ , deepseq >= 1.4+ , language-nix > 2+ , lens+ , pretty >= 1.1.2+ , process+ , split+ , distribution-nixpkgs+ , doctest+ , hspec+ , QuickCheck+ default-language: Haskell2010
+ src/Distribution/Nixpkgs/License.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE DeriveGeneric #-}++{- |+ 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.Nixpkgs.License ( License(..) ) where++import Control.DeepSeq+import Data.Maybe+import GHC.Generics ( Generic )+import Language.Nix.PrettyPrinting++-- | 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 tat+-- situation, the 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, Generic)++instance Pretty License where+ pPrint (Known x) = text x+ pPrint (Unknown x) = string (fromMaybe "unknown" x)++instance NFData License
+ src/Distribution/Nixpkgs/Meta.hs view
@@ -0,0 +1,100 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TemplateHaskell #-}++{- |+ 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.Nixpkgs.Meta+ ( Meta, nullMeta+ , homepage, description, license, platforms, hydraPlatforms, maintainers, broken+ , allKnownPlatforms+ ) where++import Control.DeepSeq+import Control.Lens+import Data.Set ( Set )+import qualified Data.Set as Set+import Distribution.Nixpkgs.License+import Distribution.System+import GHC.Generics ( Generic )+import Internal.OrphanInstances ( )+import Language.Nix.Identifier+import Language.Nix.PrettyPrinting++-- | A representation of the @meta@ section used in Nix expressions.+--+-- >>> :set -XOverloadedStrings+-- >>> :{+-- print (pPrint (Meta "http://example.org" "an example package" (Unknown Nothing)+-- (Set.singleton (Platform X86_64 Linux))+-- Set.empty+-- (Set.fromList ["joe","jane"])+-- True))+-- :}+-- homepage = "http://example.org";+-- description = "an example package";+-- license = "unknown";+-- platforms = [ "x86_64-linux" ];+-- hydraPlatforms = stdenv.lib.platforms.none;+-- maintainers = with stdenv.lib.maintainers; [ jane joe ];+-- broken = true;++data Meta = Meta+ { _homepage :: String -- ^ URL of the package homepage+ , _description :: String -- ^ short description of the package+ , _license :: License -- ^ licensing terms+ , _platforms :: Set Platform -- ^ We re-use the Cabal type for convenience, but render it to conform to @pkgs\/lib\/platforms.nix@.+ , _hydraPlatforms :: Set Platform -- ^ list of platforms built by Hydra (render to conform to @pkgs\/lib\/platforms.nix@)+ , _maintainers :: Set Identifier -- ^ list of maintainers from @pkgs\/lib\/maintainers.nix@+ , _broken :: Bool -- ^ set to @true@ if the build is known to fail+ }+ deriving (Show, Eq, Ord, Generic)++makeLenses ''Meta++instance NFData Meta++instance Pretty Meta where+ pPrint Meta {..} = vcat+ [ onlyIf (not (null _homepage)) $ attr "homepage" $ string _homepage+ , onlyIf (not (null _description)) $ attr "description" $ string _description+ , attr "license" $ pPrint _license+ , onlyIf (_platforms /= allKnownPlatforms) $ renderPlatforms "platforms" _platforms+ , onlyIf (_hydraPlatforms /= _platforms) $ renderPlatforms "hydraPlatforms" _hydraPlatforms+ , setattr "maintainers" (text "with stdenv.lib.maintainers;") (Set.map (view ident) _maintainers)+ , boolattr "broken" _broken _broken+ ]++renderPlatforms :: String -> Set Platform -> Doc+renderPlatforms field ps+ | Set.null ps = sep [ text field <+> equals <+> text "stdenv.lib.platforms.none" <> semi ]+ | otherwise = sep [ text field <+> equals <+> lbrack+ , nest 2 $ fsep $ map text (toAscList (Set.map fromCabalPlatform ps))+ , rbrack <> semi+ ]++nullMeta :: Meta+nullMeta = Meta+ { _homepage = error "undefined Meta.homepage"+ , _description = error "undefined Meta.description"+ , _license = error "undefined Meta.license"+ , _platforms = error "undefined Meta.platforms"+ , _hydraPlatforms = error "undefined Meta.hydraPlatforms"+ , _maintainers = error "undefined Meta.maintainers"+ , _broken = error "undefined Meta.broken"+ }++allKnownPlatforms :: Set Platform+allKnownPlatforms = Set.fromList [ Platform I386 Linux, Platform X86_64 Linux+ , Platform X86_64 OSX+ ]++fromCabalPlatform :: Platform -> String+fromCabalPlatform (Platform I386 Linux) = "\"i686-linux\""+fromCabalPlatform (Platform X86_64 Linux) = "\"x86_64-linux\""+fromCabalPlatform (Platform X86_64 OSX) = "\"x86_64-darwin\""+fromCabalPlatform p = error ("fromCabalPlatform: invalid Nix platform" ++ show p)
+ src/Distribution/Nixpkgs/PackageMap.hs view
@@ -0,0 +1,59 @@+module Distribution.Nixpkgs.PackageMap+ ( PackageMap, readNixpkgPackageMap+ , resolve+ ) where++import qualified Data.Aeson as JSON+import qualified Data.ByteString.Lazy as LBS+import Data.Function+import Data.List as List+import Data.List.Split+import qualified Data.Map.Strict as Map+import Data.Map.Strict ( Map )+import Data.Maybe+import Data.Set ( Set )+import qualified Data.Set as Set+import Distribution.Text+import Language.Nix+import System.Process+import Control.Lens++type PackageMap = Map Identifier (Set Path)++readNixpkgPackageMap :: FilePath -> Maybe Path -> IO PackageMap+readNixpkgPackageMap nixpkgs attrpath = fmap identifierSet2PackageMap (readNixpkgSet nixpkgs attrpath)++readNixpkgSet :: FilePath -> Maybe Path -> IO (Set String)+readNixpkgSet nixpkgs attrpath = do+ let extraArgs = maybe [] (\p -> ["-A", display p]) attrpath+ (_, Just h, _, _) <- createProcess (proc "nix-env" (["-qaP", "--json", "-f", nixpkgs] ++ extraArgs))+ { std_out = CreatePipe, env = Nothing } -- TODO: ensure that overrides don't screw up our results+ buf <- LBS.hGetContents h+ let pkgmap :: Either String (Map String JSON.Object)+ pkgmap = JSON.eitherDecode buf+ either fail (return . Map.keysSet) pkgmap++identifierSet2PackageMap :: Set String -> PackageMap+identifierSet2PackageMap pkgset = foldr (uncurry insertIdentifier) Map.empty pkglist+ where+ pkglist :: [(Identifier, Path)]+ pkglist = mapMaybe parsePackage (Set.toList pkgset)++ insertIdentifier :: Identifier -> Path -> PackageMap -> PackageMap+ insertIdentifier i = Map.insertWith Set.union i . Set.singleton++parsePackage :: String -> Maybe (Identifier, Path)+parsePackage x | null x = error "Distribution.Nixpkgs.PackageMap.parsepackage: empty string is no valid identifier"+ | xs <- splitOn "." x = if needsQuoting (head xs)+ then Nothing+ else Just (ident # last xs, path # map (review ident) xs)++resolve :: PackageMap -> Identifier -> Maybe Binding+resolve nixpkgs i = case Map.lookup i nixpkgs of+ Nothing -> Nothing+ Just ps -> let p = chooseShortestPath (Set.toList ps)+ in Just $ binding # (i,p)++chooseShortestPath :: [Path] -> Path+chooseShortestPath [] = error "chooseShortestPath: called with empty list argument"+chooseShortestPath ps = minimumBy (on compare (view (path . to length))) ps
+ src/Internal/OrphanInstances.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE DeriveGeneric #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Internal.OrphanInstances ( ) where++import Control.DeepSeq+import Distribution.System++instance NFData Arch+instance NFData OS+instance NFData Platform
+ src/Language/Nix/PrettyPrinting.hs view
@@ -0,0 +1,62 @@+-- | Internal pretty-printing helpers for Nix expressions.++module Language.Nix.PrettyPrinting+ ( onlyIf+ , setattr, toAscList+ , listattr+ , boolattr+ , attr+ , string+ , funargs+ -- * Re-exports from other modules+ , module Text.PrettyPrint.HughesPJClass+ , Text, disp+ )+ where++import Data.Char+import Data.Function+import Data.List+import Data.Set ( Set )+import qualified Data.Set as Set+import Distribution.Text ( Text, disp )+import Text.PrettyPrint.HughesPJClass++attr :: String -> Doc -> Doc+attr n v = text n <+> equals <+> v <> semi++onlyIf :: Bool -> Doc -> Doc+onlyIf b d = if b 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 (not (null vs)) $+ sep [ text n <+> equals <+> prefix <+> lbrack,+ nest 2 $ fsep $ map text vs,+ rbrack <> semi+ ]++setattr :: String -> Doc -> Set String -> Doc+setattr name prefix set = listattr name prefix (toAscList set)++toAscList :: Set String -> [String]+toAscList = sortBy (compare `on` map toLower) . Set.toList++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+ ]
+ test/Main.hs view
@@ -0,0 +1,32 @@+module Main ( main ) where++import Control.DeepSeq+import Control.Exception+import Control.Lens+import Data.Maybe+import Distribution.Nixpkgs.License+import Distribution.Nixpkgs.Meta+import System.Environment+import Test.DocTest+import Test.Hspec++main :: IO ()+main = do+ distDir <- fromMaybe "dist" `fmap` lookupEnv "HASKELL_DIST_DIR"+ let cabalMacrosHeader = distDir ++ "/build/autogen/cabal_macros.h"+ doctest [ "-isrc", "-optP-include", "-optP"++cabalMacrosHeader, "src" ]++ hspec $+ describe "DeepSeq instances work properly for" $ do+ it "License" $ mapM_ hitsBottom [Known undefined, Unknown (Just undefined)]+ it "Meta" $ mapM_ hitsBottom+ [ nullMeta & homepage .~ undefined+ , nullMeta & description .~ undefined+ , nullMeta & license .~ undefined+ , nullMeta & platforms .~ undefined+ , nullMeta & maintainers .~ undefined+ , nullMeta & broken .~ undefined+ ]++hitsBottom :: NFData a => a -> Expectation+hitsBottom x = evaluate (rnf x) `shouldThrow` anyErrorCall