cabal-doctest (empty) → 1
raw patch · 6 files changed
+398/−0 lines, 6 filesdep +Cabaldep +basedep +directorysetup-changed
Dependencies added: Cabal, base, directory, filepath
Files
- ChangeLog.md +3/−0
- LICENSE +30/−0
- README.md +71/−0
- Setup.hs +2/−0
- cabal-doctest.cabal +46/−0
- src/Distribution/Extra/Doctest.hs +246/−0
+ ChangeLog.md view
@@ -0,0 +1,3 @@+# 1 -- 2017-01-31++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2017, Oleg Grenrus++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 Oleg Grenrus 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.
+ README.md view
@@ -0,0 +1,71 @@+cabal-doctest+-------------++[](https://hackage.haskell.org/package/cabal-doctest) [](https://travis-ci.org/phadej/cabal-doctest)++A `Setup.hs` helper for running `doctests`.++Example Usage+=============++To use this library in your `Setup.hs`, you should specify a `custom-setup`+section in your `.cabal` file. For example:++```+custom-setup+ setup-depends:+ base >= 4 && <5,+ cabal-doctest >= 1 && <1.1+```++You'll also need to specify `build-type: Custom` at the top of the `.cabal`+file. Now put this into your `Setup.hs` file:++```haskell+module Main where++import Distribution.Extra.Doctest (defaultMainWithDoctests)++main :: IO ()+main = defaultMainWithDoctests "doctests"+```++When you build your project, this `Setup` will generate a `Build_doctests`+module. To use it in a testsuite, simply do this:++```haskell+module Main where++import Build_doctests (flags, pkgs, module_sources)+import Data.Foldable (traverse_)+import Test.Doctest (doctest)++main :: IO ()+main = do+ traverse_ putStrLn args -- optionally print arguments+ doctest args+ where+ args = flags ++ pkgs ++ module_sources+```++Notes+=====++* `custom-setup` section is supported starting from `cabal-install-1.24`.+ For older `cabal-install's` you have to install custom setup dependencies+ manually.++* `stack` respects `custom-setup` starting from version 1.3.3. Before that+ you have to use `explicit-setup-deps` setting in your `stack.yaml`.+ ([stack/GH-2094](https://github.com/commercialhaskell/stack/issues/2094))++* There is [an issue in the Cabal issue tracker](https://github.com/haskell/cabal/issues/2327 Cabal/2327)+ about adding `cabal doctest` command. After that command is implemented,+ this library will be deprecated.++Copyright+=========++Copyright 2017 Oleg Grenrus.++Available under the BSD 3-clause license.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ cabal-doctest.cabal view
@@ -0,0 +1,46 @@+name: cabal-doctest+version: 1+synopsis: A Setup.hs helper for doctests running+description:+ Currently (beginning of 2017), there isn't @cabal doctest@+ command. Yet, to properly work doctest needs plenty of configuration.+ This library provides the common bits for writing custom Setup.hs++ See <https://github.com/haskell/cabal/issues/2327 Cabal/2327> for the progress+ of @cabal doctest@, i.e. whether this library is obsolete.++homepage: https://github.com/phadej/cabal-doctests+license: BSD3+license-file: LICENSE+author: Oleg Grenrus <oleg.grenrus@iki.fi>+maintainer: Oleg Grenrus <oleg.grenrus@iki.fi>+copyright: (c) 2017 Oleg Grenrus+category: Distribution+build-type: Simple+cabal-version: >=1.10+extra-source-files: ChangeLog.md README.md+tested-with:+ GHC==7.0.4,+ GHC==7.2.2,+ GHC==7.4.2,+ GHC==7.6.3,+ GHC==7.8.4,+ GHC==7.10.3,+ GHC==8.0.2,+ GHC==8.1.*++source-repository head+ type: git+ location: https://github.com/phadej/cabal-doctest++library+ exposed-modules: Distribution.Extra.Doctest+ other-modules:+ other-extensions:+ build-depends:+ base >=4.3 && <4.11,+ Cabal >= 1.10 && <2.1,+ filepath,+ directory+ hs-source-dirs: src+ default-language: Haskell2010
+ src/Distribution/Extra/Doctest.hs view
@@ -0,0 +1,246 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+-- | The provided 'generateBuildModule' generates 'Build_doctests' module.+-- That module exports enough configuration, so your doctests could be simply+--+-- @+-- module Main where+-- +-- import Build_doctests (flags, pkgs, module_sources)+-- import Data.Foldable (traverse_)+-- import Test.Doctest (doctest)+-- +-- main :: IO ()+-- main = do+-- traverse_ putStrLn args -- optionally print arguments+-- doctest args+-- where+-- args = flags ++ pkgs ++ module_sources+-- @+--+-- To use this library in the @Setup.hs@, you should specify a @custom-setup@ +-- section in the cabal file, for example:+--+-- @+-- custom-setup+-- setup-depends:+-- base >= 4 && <5,+-- cabal-doctest >= 1 && <1.1+-- @+--+-- /Note:/ you don't need to depend on @Cabal@ if you use only+-- 'defaultMainWithDoctests' in the @Setup.hs".+--+module Distribution.Extra.Doctest (+ defaultMainWithDoctests,+ doctestsUserHooks,+ generateBuildModule,+ ) where++-- Hacky way to suppress few deprecation warnings.+#if MIN_VERSION_Cabal(1,24,0)+#define InstalledPackageId UnitId+#endif++import Control.Monad+ (when)+import Data.List+ (nub)+import Data.String+ (fromString)+import Distribution.Package+ (InstalledPackageId)+import Distribution.Package+ (Package (..), PackageId, packageVersion)+import Distribution.PackageDescription+ (BuildInfo (..), Library (..), PackageDescription (), TestSuite (..))+import Distribution.Simple+ (UserHooks (..), defaultMainWithHooks, simpleUserHooks)+import Distribution.Simple.BuildPaths+ (autogenModulesDir)+import Distribution.Simple.Compiler+ (PackageDB (..), showCompilerId)+import Distribution.Simple.LocalBuildInfo+ (ComponentLocalBuildInfo (componentPackageDeps), LocalBuildInfo (),+ compiler, withLibLBI, withPackageDB, withTestLBI)+import Distribution.Simple.Setup+ (BuildFlags (buildDistPref, buildVerbosity), fromFlag)+import Distribution.Simple.Utils+ (createDirectoryIfMissingVerbose, rewriteFile)+import Distribution.Text+ (display, simpleParse)+import System.FilePath+ ((</>))++#if MIN_VERSION_Cabal(1,25,0)+import Distribution.Simple.BuildPaths+ (autogenComponentModulesDir)+#endif++#if MIN_VERSION_directory(1,2,2)+import System.Directory+ (makeAbsolute)+#else+import System.Directory+ (getCurrentDirectory)+import System.FilePath+ (isAbsolute)++makeAbsolute :: FilePath -> IO FilePath+makeAbsolute p | isAbsolute p = return p+ | otherwise = do+ cwd <- getCurrentDirectory+ return $ cwd </> p+#endif++-- | A default main with doctests:+--+-- @+-- import Distribution.Extra.Doctest+-- (defaultMainWithDoctests)+--+-- main :: IO ()+-- main = defaultMainWithDoctests "doctests"+-- @+defaultMainWithDoctests+ :: String -- ^ doctests test-suite name+ -> IO ()+defaultMainWithDoctests = defaultMainWithHooks . doctestsUserHooks++-- | 'simpleUserHooks' with 'generateBuildModule' prepended to the 'buildHook'.+doctestsUserHooks+ :: String -- ^ doctests test-suite name+ -> UserHooks+doctestsUserHooks testsuiteName = simpleUserHooks+ { buildHook = \pkg lbi hooks flags -> do+ generateBuildModule testsuiteName flags pkg lbi+ buildHook simpleUserHooks pkg lbi hooks flags+ }++-- | Generate a build module for the test suite.+--+-- @+-- import Distribution.Simple+-- (defaultMainWithHooks, UserHooks(..), simpleUserHooks)+-- import Distribution.Extra.Doctest+-- (generateBuildModule)+--+-- main :: IO ()+-- main = defaultMainWithHooks simpleUserHooks+-- { buildHook = \pkg lbi hooks flags -> do+-- generateBuildModule "doctests" flags pkg lbi+-- buildHook simpleUserHooks pkg lbi hooks flags+-- }+-- @+generateBuildModule+ :: String -- ^ doctests test-suite name+ -> BuildFlags -> PackageDescription -> LocalBuildInfo -> IO ()+generateBuildModule testSuiteName flags pkg lbi = do+ let verbosity = fromFlag (buildVerbosity flags)+ let distPref = fromFlag (buildDistPref flags)++ -- Package DBs+ let dbStack = withPackageDB lbi ++ [ SpecificPackageDB $ distPref </> "package.conf.inplace" ]+ let dbFlags = "-hide-all-packages" : packageDbArgs dbStack++ withLibLBI pkg lbi $ \lib libcfg -> do+ let libBI = libBuildInfo lib++ -- modules+ let modules = exposedModules lib ++ otherModules libBI+ -- it seems that doctest is happy to take in module names, not actual files!+ let module_sources = modules++ -- We need the directory with library's cabal_macros.h!+#if MIN_VERSION_Cabal(1,25,0)+ let libAutogenDir = autogenComponentModulesDir lbi libcfg+#else+ let libAutogenDir = autogenModulesDir lbi+#endif++ -- Lib sources and includes+ iArgs <- mapM (fmap ("-i"++) . makeAbsolute) $ libAutogenDir : hsSourceDirs libBI+ includeArgs <- mapM (fmap ("-I"++) . makeAbsolute) $ includeDirs libBI++ -- CPP includes, i.e. include cabal_macros.h+ let cppFlags = map ("-optP"++) $+ [ "-include", libAutogenDir ++ "/cabal_macros.h" ]+ ++ cppOptions libBI++ withTestLBI pkg lbi $ \suite suitecfg -> when (testName suite == fromString testSuiteName) $ do++ -- get and create autogen dir+#if MIN_VERSION_Cabal(1,25,0)+ let testAutogenDir = autogenComponentModulesDir lbi suitecfg+#else+ let testAutogenDir = autogenModulesDir lbi+#endif+ createDirectoryIfMissingVerbose verbosity True testAutogenDir++ -- write autogen'd file+ rewriteFile (testAutogenDir </> "Build_doctests.hs") $ unlines+ [ "module Build_doctests where"+ , ""+ -- -package-id etc. flags+ , "pkgs :: [String]"+ , "pkgs = " ++ (show $ formatDeps $ testDeps libcfg suitecfg)+ , ""+ , "flags :: [String]"+ , "flags = " ++ show (iArgs ++ includeArgs ++ dbFlags ++ cppFlags)+ , ""+ , "module_sources :: [String]"+ , "module_sources = " ++ show (map display module_sources)+ ]+ where+ -- we do this check in Setup, as then doctests don't need to depend on Cabal+ isOldCompiler = maybe False id $ do+ a <- simpleParse $ showCompilerId $ compiler lbi+ b <- simpleParse "7.5"+ return $ packageVersion (a :: PackageId) < b++ formatDeps = map formatOne+ formatOne (installedPkgId, pkgId)+ -- The problem is how different cabal executables handle package databases+ -- when doctests depend on the library+ | packageId pkg == pkgId = "-package=" ++ display pkgId+ | otherwise = "-package-id=" ++ display installedPkgId++ -- From Distribution.Simple.Program.GHC+ packageDbArgs :: [PackageDB] -> [String]+ packageDbArgs | isOldCompiler = packageDbArgsConf+ | otherwise = packageDbArgsDb++ -- GHC <7.6 uses '-package-conf' instead of '-package-db'.+ packageDbArgsConf :: [PackageDB] -> [String]+ packageDbArgsConf dbstack = case dbstack of+ (GlobalPackageDB:UserPackageDB:dbs) -> concatMap specific dbs+ (GlobalPackageDB:dbs) -> ("-no-user-package-conf")+ : concatMap specific dbs+ _ -> ierror+ where+ specific (SpecificPackageDB db) = [ "-package-conf=" ++ db ]+ specific _ = ierror+ ierror = error $ "internal error: unexpected package db stack: "+ ++ show dbstack++ -- GHC >= 7.6 uses the '-package-db' flag. See+ -- https://ghc.haskell.org/trac/ghc/ticket/5977.+ packageDbArgsDb :: [PackageDB] -> [String]+ -- special cases to make arguments prettier in common scenarios+ packageDbArgsDb dbstack = case dbstack of+ (GlobalPackageDB:UserPackageDB:dbs)+ | all isSpecific dbs -> concatMap single dbs+ (GlobalPackageDB:dbs)+ | all isSpecific dbs -> "-no-user-package-db"+ : concatMap single dbs+ dbs -> "-clear-package-db"+ : concatMap single dbs+ where+ single (SpecificPackageDB db) = [ "-package-db=" ++ db ]+ single GlobalPackageDB = [ "-global-package-db" ]+ single UserPackageDB = [ "-user-package-db" ]+ isSpecific (SpecificPackageDB _) = True+ isSpecific _ = False++testDeps :: ComponentLocalBuildInfo -> ComponentLocalBuildInfo -> [(InstalledPackageId, PackageId)]+testDeps xs ys = nub $ componentPackageDeps xs ++ componentPackageDeps ys