Converting .cabal files to .json
Someone on #haskell last night was looking for a tool to convert a cabal-install package description to JSON. I hacked something together a while back to do exactly this for the cabal-waf project. While it’s not worthy of a standalone release on hackage it might be useful for someone else out there.
The source is also available for your cloning pleasure on GitHub. Enjoy.
{-# OPTIONS_GHC -fno-warn-deprecations #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE TemplateHaskell #-}
module Main (main) where
import Control.Monad (when)
import qualified Data.ByteString.Lazy as BL
import Data.List
import Data.Aeson
import Data.Aeson.TH
import Distribution.ModuleName (ModuleName)
import Distribution.Package
import Distribution.PackageDescription
import Distribution.PackageDescription.Configuration
import Distribution.PackageDescription.Parse (readPackageDescription)
import Distribution.Verbosity
import Distribution.Version
import Distribution.License
import Distribution.Compiler
import Language.Haskell.Extension
import System.Environment (getArgs)
deriveJSON id ''PackageDescription
deriveJSON id ''PackageIdentifier
deriveJSON id ''PackageName
deriveJSON id ''Version
deriveJSON id ''SourceRepo
deriveJSON id ''RepoKind
deriveJSON id ''RepoType
deriveJSON id ''BuildType
deriveJSON id ''Library
deriveJSON id ''Executable
deriveJSON id ''TestSuite
deriveJSON id ''License
deriveJSON id ''CompilerFlavor
deriveJSON id ''TestSuiteInterface
deriveJSON id ''BuildInfo
deriveJSON id ''ModuleName
deriveJSON id ''Dependency
deriveJSON id ''Language
deriveJSON id ''Extension
deriveJSON id ''KnownExtension
deriveJSON id ''TestType
deriveJSON id ''VersionRange
main :: IO ()
main = do
args <- getArgs
when (length args == 0) $ fail "missing .cabal file"
let (source:_) = args
gdesc <- readPackageDescription normal source
let desc = flattenPackageDescription gdesc
bs = encode . toJSON $ desc
BL.putStrLn bs
Running it on a small-ish .cabal file…
name: ghc-prim
version: 0.2.0.0
license: BSD3
license-file: LICENSE
maintainer: libraries@haskell.org
bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=libraries%20%28other%29
synopsis: GHC primitives
description:
GHC primitives.
cabal-version: >=1.6
build-type: Custom
source-repository head
type: git
location: http://darcs.haskell.org/packages/ghc-prim.git/
flag include-ghc-prim {
Description: Include GHC.Prim in exposed-modules
default: False
}
Library {
build-depends: rts
exposed-modules:
GHC.Classes
GHC.CString
GHC.Debug
GHC.Generics
GHC.Magic
GHC.PrimopWrappers
GHC.IntWord64
GHC.Tuple
GHC.Types
if flag(include-ghc-prim) {
exposed-modules: GHC.Prim
}
c-sources:
cbits/debug.c
cbits/longlong.c
cbits/popcnt.c
extensions: CPP, MagicHash, ForeignFunctionInterface, UnliftedFFITypes,
UnboxedTuples, EmptyDataDecls, NoImplicitPrelude
-- We need to set the package name to ghc-prim (without a version number)
-- as it's magic.
ghc-options: -package-name ghc-prim
}
Produces output that is easier to consume outside of Haskell. It’s worth noting that conditional statements in the .cabal script are resolved, so the if flag statement above results in GHC.Prim being listed as an exposedModule.
{
"author": "",
"bugReports": "http://hackage.haskell.org/trac/ghc/newticket?component=libraries%20%28other%29",
"buildDepends": [["rts", { "AnyVersion": [] }]],
"buildType": { "Custom": [] },
"category": "",
"copyright": "",
"customFieldsPD": [],
"dataDir": "",
"dataFiles": [],
"description": "GHC primitives.",
"executables": [],
"extraSrcFiles": [],
"extraTmpFiles": [],
"homepage": "",
"library": {
"exposedModules": [
["GHC", "Classes"],
["GHC", "CString"],
["GHC", "Debug"],
["GHC", "Generics"],
["GHC", "Magic"],
["GHC", "PrimopWrappers"],
["GHC", "IntWord64"],
["GHC", "Tuple"],
["GHC", "Types"],
["GHC", "Prim"]
],
"libBuildInfo": {
"buildTools": [],
"buildable": true,
"cSources": ["cbits/debug.c", "cbits/longlong.c", "cbits/popcnt.c"],
"ccOptions": [],
"cppOptions": [],
"customFieldsBI": [],
"defaultExtensions": [],
"defaultLanguage": null,
"extraLibDirs": [],
"extraLibs": [],
"frameworks": [],
"ghcProfOptions": [],
"ghcSharedOptions": [],
"hsSourceDirs": ["."],
"includeDirs": [],
"includes": [],
"installIncludes": [],
"ldOptions": [],
"oldExtensions": [
{ "EnableExtension": { "CPP": [] } },
{ "EnableExtension": { "MagicHash": [] } },
{ "EnableExtension": { "ForeignFunctionInterface": [] } },
{ "EnableExtension": { "UnliftedFFITypes": [] } },
{ "EnableExtension": { "UnboxedTuples": [] } },
{ "EnableExtension": { "EmptyDataDecls": [] } },
{ "DisableExtension": { "ImplicitPrelude": [] } }
],
"options": [[{ "GHC": [] }, ["-package-name", "ghc-prim"]]],
"otherExtensions": [],
"otherLanguages": [],
"otherModules": [],
"pkgconfigDepends": [],
"targetBuildDepends": []
},
"libExposed": true
},
"license": { "BSD3": [] },
"licenseFile": "LICENSE",
"maintainer": "libraries@haskell.org",
"package": {
"pkgName": "ghc-prim",
"pkgVersion": { "versionBranch": [0, 2, 0, 0], "versionTags": [] }
},
"pkgUrl": "",
"sourceRepos": [
{
"repoBranch": null,
"repoKind": { "RepoHead": [] },
"repoLocation": "http://darcs.haskell.org/packages/ghc-prim.git/",
"repoModule": null,
"repoSubdir": null,
"repoTag": null,
"repoType": { "Git": [] }
}
],
"specVersionRaw": {
"Right": {
"UnionVersionRanges": [
{ "ThisVersion": { "versionBranch": [1, 6], "versionTags": [] } },
{ "LaterVersion": { "versionBranch": [1, 6], "versionTags": [] } }
]
}
},
"stability": "",
"synopsis": "GHC primitives",
"testSuites": [],
"testedWith": []
}