module Data.ProtoLens.Setup
( defaultMainGeneratingProtos
, generatingProtos
, generateProtos
) where
import Distribution.PackageDescription
( PackageDescription(..)
, benchmarkBuildInfo
, buildInfo
, extraSrcFiles
, hsSourceDirs
, libBuildInfo
, testBuildInfo
)
import Distribution.Simple.BuildPaths (autogenModulesDir)
import Distribution.Simple.LocalBuildInfo (LocalBuildInfo)
import Distribution.Simple.Program (knownPrograms, ConfiguredProgram(..))
import Distribution.Simple.Program.Types (simpleProgram)
import Distribution.Simple.Utils (matchFileGlob)
import Distribution.Simple
( defaultMainWithHooks
, simpleUserHooks
, UserHooks(..)
)
import System.FilePath
( (</>)
, equalFilePath
, isRelative
, makeRelative
, takeExtension
)
import System.Directory (createDirectoryIfMissing, findExecutable)
import System.Process (callProcess)
defaultMainGeneratingProtos
:: FilePath
-> IO ()
defaultMainGeneratingProtos root
= defaultMainWithHooks $ generatingProtos root simpleUserHooks
generatingProtos
:: FilePath
-> UserHooks -> UserHooks
generatingProtos root hooks = hooks
{ buildHook = \p l h f -> generateSources p l >> buildHook hooks p l h f
, haddockHook = \p l h f -> generateSources p l >> haddockHook hooks p l h f
, replHook = \p l h f args -> generateSources p l
>> replHook hooks p l h f args
, sDistHook = \p maybe_l h f -> case maybe_l of
Nothing -> error "Can't run protoc; run 'cabal configure' first."
Just l -> do
generateSources p l
sDistHook hooks (fudgePackageDesc l p) maybe_l h f
}
where
generateSources p l = do
files <- concat <$> mapM matchFileGlob (extraSrcFiles p)
generateProtos root (autogenModulesDir l)
$ filter (isSubdirectoryOf root)
$ filter (\f -> takeExtension f == ".proto")
files
fudgePackageDesc :: LocalBuildInfo -> PackageDescription -> PackageDescription
fudgePackageDesc lbi p = p
{ library =
(\lib -> lib { libBuildInfo = fudgeBuildInfo (libBuildInfo lib) })
<$> library p
, executables =
(\exe -> exe { buildInfo = fudgeBuildInfo (buildInfo exe) })
<$> executables p
, testSuites =
(\test -> test { testBuildInfo = fudgeBuildInfo (testBuildInfo test) })
<$> testSuites p
, benchmarks =
(\bench -> bench { benchmarkBuildInfo =
fudgeBuildInfo (benchmarkBuildInfo bench) })
<$> benchmarks p
}
where
fudgeBuildInfo bi =
bi { hsSourceDirs = autogenModulesDir lbi : hsSourceDirs bi }
isSubdirectoryOf :: FilePath -> FilePath -> Bool
isSubdirectoryOf root f
= isRelative f
&& equalFilePath f (root </> makeRelative root f)
generateProtos
:: FilePath
-> FilePath
-> [FilePath]
-> IO ()
generateProtos root output files = do
maybeProtoLensProtoc <- findExecutable "proto-lens-protoc"
case maybeProtoLensProtoc of
Nothing -> error "Couldn't find executable proto-lens-protoc."
Just protoLensProtoc -> do
createDirectoryIfMissing True output
callProcess "protoc" $
[ "--plugin=protoc-gen-haskell=" ++ protoLensProtoc
, "--haskell_out=" ++ output
, "--proto_path=" ++ root
]
++ files