cabal-query (empty) → 0.1
raw patch · 6 files changed
+238/−0 lines, 6 filesdep +Cabaldep +MissingHdep +basesetup-changed
Dependencies added: Cabal, MissingH, base, bytestring, derive, ghc, mtl, tar, template-haskell, uniplate
Files
- LICENSE +29/−0
- Setup.hs +2/−0
- cabal-query.cabal +30/−0
- src/Distribution/Query.hs +88/−0
- src/Distribution/Query/TH.hs +8/−0
- src/Distribution/Query/Types.hs +81/−0
+ LICENSE view
@@ -0,0 +1,29 @@+Copyright (c) 2009, Max Desyatov+All rights reserved.++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.++ * Neither the name of the author nor the names of his contributors+ may 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.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ cabal-query.cabal view
@@ -0,0 +1,30 @@+name: cabal-query+version: 0.1+copyright: (c) 2009 Max Desyatov+category: System+maintainer: Max Desyatov <explicitcall at gmail.com>+author: Max Desyatov+license: BSD3+license-file: LICENSE+cabal-version: >= 1.6+synopsis: Helpers for quering .cabal files or hackageDB's 00-index.tar+description: This package was written to assist you at finding a set of packages,+ which satisfy your needs. At the moment it doesn't have a standalone executable,+ but you can do the queries from your Haskell code.+stability: Experimental+build-type: Simple+homepage: http://github.com/explicitcall/cabal-query+bug-reports: http://github.com/explicitcall/cabal-query/issues++library+ exposed-modules: Distribution.Query+ other-modules: Distribution.Query.TH,+ Distribution.Query.Types+ hs-source-dirs: src+ ghc-options: -Wall -fno-warn-orphans+ build-depends: base >= 4 && < 5, mtl, template-haskell, derive, Cabal >= 1.6 && < 1.7,+ MissingH, uniplate, bytestring, tar, ghc >= 6.10 && < 6.11++source-repository head+ type: git+ location: git://github.com/explicitcall/cabal-query.git
+ src/Distribution/Query.hs view
@@ -0,0 +1,88 @@+{-# LANGUAGE ScopedTypeVariables #-}++-- | This package uses "Data.Generics.PlateData", so+--+-- * when Cabal package format changes, we don't have to rewrite anything+--+-- * all queries are statically typed+--+-- * as a disadvantage, we may suffer some performance loss when doing very complex queries,+-- anyway most of processing goes while we read package descriptions, not querying them+--+-- Example of enduser querying code:+--+-- @+--module Main where+--+-- import qualified Data.ByteString.Lazy as B+--import System.Environment+--import Distribution.Query+--import Distribution.Compiler+--import Distribution.License+--import Distribution.ModuleName hiding (main)+--import Distribution.Package+--import Distribution.PackageDescription+--import Distribution.Version+--import Distribution.Text+--import Language.Haskell.Extension+--+-- main = (head \`fmap\` getArgs) >>=+-- B.readFile >>=+-- mapM_ (putStrLn . show . (\x -> (display $ package x, display $ license x))) .+-- queryIndex (Not (Id (== GPL)) :& Not (Id (== BSD3)))+-- @+--+-- You can query any field of 'PackageDescription' no matter how deep it is.+-- You don't need to provide any type signature for comparison functions,+-- which are wrapped in 'Id', as long as you use data constructors for which type can be inferred.+--+-- See 'PackageDescription' fields for details.+module Distribution.Query+ ( queryFiles+ , queryIndex+ , module Distribution.Query.Types ) where++import Codec.Archive.Tar as T hiding (unpack)+import Data.ByteString.Internal (w2c)+import Data.ByteString.Lazy (ByteString)+import qualified Data.ByteString.Lazy as B+import Data.Generics.PlateData+import Data.Maybe+import Distribution.PackageDescription+import Distribution.PackageDescription.Parse++import Distribution.Query.Types++-- | Queries an index file, which is commonly located at+-- <~/.cabal/packages/hackage.haskell.org/00-index.tar> in POSIX systems.+queryIndex :: Query+ -> ByteString -- ^ The index file must be read as lazy ByteString+ -> [PackageDescription] -- ^ Returns a list of package descriptions which satisfy the query+queryIndex q = procQuery q . foldEntries foldF [] (const []) . T.read+ where+ foldF :: Entry -> [PackageDescription] -> [PackageDescription]+ foldF c rest =+ case entryContent c of+ NormalFile s _ -> maybe rest (:rest) $ parsePD s+ _ -> rest++parsePD :: ByteString -> Maybe PackageDescription+parsePD s =+ case (parsePackageDescription $ map w2c $ B.unpack s) of+ ParseOk _ x -> Just $ packageDescription x+ _ -> Nothing++-- | Queries .cabal files.+queryFiles :: Query+ -> [ByteString] -- ^ All files must be read as lazy ByteStrings+ -> [PackageDescription] -- ^ Returns a list of package descriptions which satisfy the query+queryFiles q = procQuery q . catMaybes . map parsePD++procQuery :: Query -> [PackageDescription] -> [PackageDescription]+procQuery q = filter (doQuery q)++doQuery :: Query -> PackageDescription -> Bool+doQuery (Id f) pd = or [f x | x <- universeBi pd]+doQuery (Not q) pd = not $ doQuery q pd+doQuery (q1 :& q2) pd = doQuery q1 pd && doQuery q2 pd+doQuery (q1 :| q2) pd = doQuery q1 pd || doQuery q2 pd
+ src/Distribution/Query/TH.hs view
@@ -0,0 +1,8 @@+module Distribution.Query.TH where++import MonadUtils+import Data.DeriveTH+import Language.Haskell.TH++deriveMany :: Derivation -> [Name] -> Q [Dec]+deriveMany = concatMapM . derive
+ src/Distribution/Query/Types.hs view
@@ -0,0 +1,81 @@+{-# LANGUAGE TemplateHaskell, GADTs #-}+module Distribution.Query.Types+ ( Query(..) ) where++import Data.Data+import Data.DeriveTH+import Data.List.Utils (join)+import Distribution.Compiler+import Distribution.License+import Distribution.ModuleName hiding (main)+import Distribution.Package+import Distribution.PackageDescription+import Distribution.Version+import Language.Haskell.Extension++import Distribution.Query.TH++-- | Heterogenous query tree. Example of constructed query:+--+-- > Not (Id (== GPL)) :& Not (Id (== BSD3))+--+-- 'Id' takes comparison function as its argument.+-- Commonly this must be a partially applied ('/=') or ('==').+-- Data instance is required for 'PackageDescription' traversal.+-- All appropriate instances are generated automagically,+-- so you don't have to bother as long as Cabal doesn't change its+-- package description format.+data Query where+ (:&) :: Query -> Query -> Query+ (:|) :: Query -> Query -> Query+ Not :: Query -> Query+ Id :: Data a => (a -> Bool) -> Query++$(deriveMany makeTypeable+ [''PackageDescription+ ,''Executable+ ,''Library+ ,''BuildType+ ,''VersionRange+ ,''Dependency+ ,''SourceRepo+ ,''CompilerFlavor+ ,''License+ ,''PackageIdentifier+ ,''BuildInfo+ ,''ModuleName+ ,''PackageName+ ,''RepoType+ ,''RepoKind+ ,''Extension])++$(deriveMany makeData+ [''PackageDescription+ ,''Executable+ ,''Library+ ,''BuildType+ ,''VersionRange+ ,''Dependency+ ,''SourceRepo+ ,''CompilerFlavor+ ,''License+ ,''PackageIdentifier+ ,''BuildInfo+ ,''PackageName+ ,''RepoType+ ,''RepoKind+ ,''Extension+ ,''Version])++-- Workaround for ModuleName, see http://code.google.com/p/ndmitchell/issues/detail?id=209+instance Data ModuleName where+ gfoldl _ z = z . simple . join "." . components+ gunfold _ z _ = z $ simple ""+ toConstr _ = con_C+ dataTypeOf _ = ty_T++con_C :: Constr+con_C = mkConstr ty_T "ModuleName" [] Prefix++ty_T :: DataType+ty_T = mkDataType "Distribution.ModuleName.ModuleName" [con_C]