gen-imports (empty) → 0.1.0.0
raw patch · 4 files changed
+199/−0 lines, 4 filesdep +Cabaldep +basedep +bytestringsetup-changed
Dependencies added: Cabal, base, bytestring, containers, filepath, hackage-db, pretty
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- gen-imports.cabal +31/−0
- src/Distribution/Hackage/Imports/Generate.hs +136/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Clinton Mead (c) 2017++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 Clinton Mead nor the names of other+ 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
+ gen-imports.cabal view
@@ -0,0 +1,31 @@+name: gen-imports+version: 0.1.0.0+synopsis: Code to generate instances for the package "ghc-instances"+description:+ Functions in this package look at the hackage database to get all the public modules of packages.++ It then creates Haskell files containing each module as an import statement.++ It's primary purpose is to produce files for the package+ [ghc-instances](https://hackage.haskell.org/package/ghc-instances).+ See that package for the motivation behind this.+homepage: https://github.com/clintonmead/gen-imports#readme+license: BSD3+license-file: LICENSE+author: Clinton Mead+maintainer: clintonmead@gmail.com+copyright: Copyright: (c) 2017 Clinton Mead+category: Web+build-type: Simple+cabal-version: >=1.10++library+ hs-source-dirs: src+ exposed-modules: Distribution.Hackage.Imports.Generate+ build-depends: base >= 4.7 && < 5, hackage-db < 2, Cabal, containers, pretty, bytestring, filepath+ default-language: Haskell2010+ ghc-options: -Wall++source-repository head+ type: git+ location: https://github.com/clintonmead/gen-imports
+ src/Distribution/Hackage/Imports/Generate.hs view
@@ -0,0 +1,136 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleInstances #-}++module Distribution.Hackage.Imports.Generate where++import Data.ByteString (ByteString)++import Distribution.Hackage.DB (Hackage, Version, readHackage)+import Distribution.PackageDescription (+ GenericPackageDescription(packageDescription, condLibrary),+ PackageDescription(library),+ Library(exposedModules),+ CondTree(CondNode, condTreeData)+ )+import Distribution.ModuleName (ModuleName)+import qualified Distribution.ModuleName+import Distribution.Version (Version(versionBranch))+import Distribution.Text (disp)+import qualified Data.Map.Lazy+import Control.Arrow (second)+import Text.PrettyPrint (Doc, text, ($+$), render)+import GHC.Exts (sortWith, Down(Down))+import Data.Monoid ((<>), mempty)+import Data.Foldable (foldl')+import System.FilePath (FilePath, (</>))+import Data.String (fromString)+import Data.Char (toUpper)+import Data.Foldable (traverse_)+import Data.List (intercalate)+import Debug.Trace (traceShowId)++type PackageName = String++class ToString a where+ toString :: a -> String++instance ToString String where+ toString = id++stringToFilePath :: String -> FilePath+stringToFilePath = id++getExposedModules :: GenericPackageDescription -> [ModuleName]+getExposedModules gpd = let+ libs1 = case library (packageDescription gpd) of+ Nothing -> []+ Just l -> exposedModules l+ libs2 = case condLibrary gpd of+ Nothing -> []+ Just (CondNode{condTreeData=l}) -> exposedModules l+ in+ libs1 ++ libs2++getExposedModulesAllVersions :: Hackage -> PackageName -> [(Version, [ModuleName])]+getExposedModulesAllVersions hackage pn = case Data.Map.Lazy.lookup pn hackage of+ Nothing -> []+ Just gpdm -> (second getExposedModules) <$> Data.Map.Lazy.toList gpdm++genImportList :: (ModuleName -> Doc) -> ModuleName -> PackageName -> [(Version, [ModuleName])] -> Doc+genImportList f moduleName packageName l = languageCpp $+$ moduleHeader $+$ guard $+$ body $+$ endIf $+$ "#endif" where+ languageCpp = "{-# LANGUAGE CPP #-}"+ guard = "#ifdef MIN_VERSION_" <> packageNameDoc+ packageNameDoc = text (replace_dash <$> toString packageName)+ moduleHeader = "module " <> disp moduleName <> " where"+ endIf = case l of+ [] -> mempty+ _ -> "#endif"+ body = (foldl' ($+$) mempty $ zipWith g ("#if":(repeat "#elif")) (sortWith Down l))+ g macro (version, module_list) = preprocessorLine $+$ modules where+ preprocessorLine = macro <> " MIN_VERSION_" <> packageNameDoc <> "(" <> v1 <> "," <> v2 <> "," <> v3 <> ")"+ modules = foldl' ($+$) mempty (f <$> module_list)+ [v1, v2, v3] = (text . show) <$> (take 3 (versionBranch version ++ [0..]))+++genImportListFromHackage :: Hackage -> ModuleName -> PackageName -> Doc+genImportListFromHackage hackage moduleName packageName = genImportList toImportLine moduleName packageName (getExposedModulesAllVersions hackage packageName) where++toImportLine :: ModuleName -> Doc+toImportLine mn = "import " <> disp mn <> " ()"++writeImportListToFile :: Hackage -> FilePath -> [String] -> PackageName -> IO ()+writeImportListToFile hackage basePath baseModuleStrList packageName =+ writeFile moduleFileName $ render (genImportListFromHackage hackage moduleName packageName) where+ capitalisedPackageName = let (s:ss) = toString packageName in fromString (((toUpper s):(replace_dash <$> ss)))+ capitalisedPackageFileName = capitalisedPackageName <> ".hs"+ moduleFileName = (foldl' (</>) basePath (map stringToFilePath baseModuleStrList)) </> capitalisedPackageFileName+ moduleName = Distribution.ModuleName.fromString ((intercalate "." baseModuleStrList) <> "." <> capitalisedPackageName)++replace_dash :: Char -> Char+replace_dash c = case c of+ '-' -> '_'+ x -> x++writeImportListsToDir :: Foldable f => FilePath -> [String] -> f PackageName -> IO ()+writeImportListsToDir basePath baseModuleStrList packageNames = do+ hackage <- readHackage+ traverse_ (writeImportListToFile hackage basePath baseModuleStrList) packageNames++writeGHCPackageImportListsToDir :: FilePath -> [String] -> IO ()+writeGHCPackageImportListsToDir basePath baseModuleStrList = writeImportListsToDir basePath baseModuleStrList ghcPackages++ghcPackages :: [PackageName]+ghcPackages = [+ "array",+ "base",+ "binary",+ "bytestring",+ "Cabal",+ "containers",+ "deepseq",+ "directory",+ "filepath",+ "ghc",+ "ghc-boot",+ "ghc-compact",+ "ghc-prim",+ "haskell98",+ "haskell2010",+ "hoopl",+ "hpc",+ "old-locale",+ "old-time",+ "integer-gmp",+ "process",+ "template-haskell",+ "time",+ "unix",+ "Win32"+ ]++{-+getExposedModulesAllVersionsIO :: PackageName -> IO [(Version, [ModuleName])]+getExposedModulesAllVersionsIO pn = do+ hackage <- readHackage+ pure $ getExposedModulesAllVersions hackage pn+-}