packages feed

cabal-auto-expose 0.1.0.0 → 0.1.0.1

raw patch · 2 files changed

+90/−40 lines, 2 files

Files

cabal-auto-expose.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.12 name: cabal-auto-expose-version: 0.1.0.0+version: 0.1.0.1 synopsis: Build time library that autodetects exposed modules description: Build time library used with a custom Setup.hs that autodetects exposed modules in the source directories of each build artifact. category: distribution,bundle,modules,library@@ -12,6 +12,7 @@ license: MIT license-file: LICENSE build-type: Simple+                           source-repository head   type: git   location: https://github.com/deech/cabal-auto-expose
src/Distribution/Simple/AutoExpose.hs view
@@ -1,5 +1,5 @@ -- | Import this module in your @Setup.hs@ to auto detect library modules in--- your project The API does not conceal it's internals but in most cases you+-- your project. The API does not conceal it's internals but in most cases you -- should only need the functions and datatype under -- 'Quick Start Functions' ("Distribution.Simple.AutoExpose#QuickStartFunctions"). -- For more granular access the ones under@@ -12,7 +12,7 @@ import Control.Monad((>=>),filterM) import Control.Monad.Extra(ifM,notM,whenJust) import Data.List(intercalate,nub)-import Distribution.Compat.Lens((%~))+import Distribution.Compat.Lens((%~),(&)) import Distribution.ModuleName(ModuleName,fromString,validModuleComponent) import Distribution.PackageDescription(hsSourceDirs,buildInfo,testBuildInfo,benchmarkBuildInfo,executables,testSuites,benchmarks,libBuildInfo,subLibraries,library,Library,GenericPackageDescription(..),HookedBuildInfo,Executable,TestSuite,Benchmark,condTreeData,packageDescription) import Distribution.Simple.BuildPaths(autogenPathsModuleName)@@ -32,6 +32,7 @@ import Distribution.Types.PackageId(PackageIdentifier(pkgName,pkgVersion)) import Distribution.Types.Version() import Distribution.PackageDescription.PrettyPrint(writeGenericPackageDescription)+import Data.Maybe(fromMaybe)  -- * Quick Start Functions #QuickStartFunctions# @@ -145,6 +146,14 @@   }   deriving Show +-- | All the exposed library components, main library and sub libraries+data AllExposed =+  AllExposed+  { allExposedMainLib :: ExposedLib+  , allExposedSubLibs :: [(Library,ExposedLib)]+  }+  deriving Show+ -- | The common pieces of 'GenericPackageDescription' and 'PackageDescription' -- which we need to auto detect Haskell modules /and/ signatures. We can't make -- do with just the 'PackageDescription' because the 'confHook' which@@ -220,71 +229,111 @@         )   pure $ moduleNamesToExpose exts contents --- | Get a list of detected Haskell modules and signatures in the main library-getExposedLib+-- | Get all the exposed modules and signatures in this project's main and sub libraries+getAllExposed   :: HasCallStack   => PackageDescriptionSubset-  -> UserHooks -- ^ So we can grab the 'hookedPreProcessors' extensions-  -> IO ExposedLib-getExposedLib pds uhs =-  let excluded =-        map libSrcDir (packageDescriptionSubsetSubLibraries pds) ++ (nonLibraryHsSourcePaths pds)-      libExposedModules l =-        getExposedModules (sourceExtensions ++ ppExts) (libSrcDir l) excluded-      libExposedSignatures l =-        getExposedModules hsigExtensions (libSrcDir l) excluded-  in case (packageDescriptionSubsetLibrary pds) of-       Nothing -> pure (ExposedLib [] [])-       Just l -> pure ExposedLib <*> (libExposedModules l) <*> (libExposedSignatures l)+  -> [String] -- ^ Custom preprocessor extensions+  -> IO AllExposed+getAllExposed pds customPPExts =+  case (packageDescriptionSubsetLibrary pds) of+    Nothing -> do+      let mainLib = ExposedLib [] []+      subLibs <- subLibsExposed []+      pure (AllExposed mainLib subLibs)+    Just l -> do+      mainLib <- mainLibExposed l+      subLibs <- subLibsExposed (libSrcDir l)+      pure (AllExposed mainLib subLibs)   where     ppExts :: [String]-    ppExts = (nub . map fst) ((hookedPreProcessors uhs) ++ knownSuffixHandlers)+    ppExts = nub (customPPExts ++ map fst knownSuffixHandlers)     libSrcDir :: Library -> [FilePath]     libSrcDir = nub . hsSourceDirs . libBuildInfo+    mainLibExcludedPaths :: [[FilePath]]+    mainLibExcludedPaths =+      (map snd subLibSrcDirs) ++ (nonLibraryHsSourcePaths pds)+    mainLibExposed :: Library -> IO ExposedLib+    mainLibExposed l = do+      exposedMods <- getExposedModules (sourceExtensions ++ ppExts) (libSrcDir l) mainLibExcludedPaths+      exposedSigs <- getExposedModules hsigExtensions (libSrcDir l) mainLibExcludedPaths+      pure (ExposedLib exposedMods exposedSigs)+    subLibSrcDirs :: [(Library,[FilePath])]+    subLibSrcDirs = zip (packageDescriptionSubsetSubLibraries pds) (map libSrcDir (packageDescriptionSubsetSubLibraries pds))+    subLibSrcDirsWithExcludedPaths :: [FilePath] -> [(Library, ([FilePath], [[FilePath]]))]+    subLibSrcDirsWithExcludedPaths mainLibSrcs =+      map (\((subLib,subLibSrcs),otherSubLibs) ->+             let excluded = (map snd otherSubLibs) ++ (nonLibraryHsSourcePaths pds) ++ [mainLibSrcs]+             in (subLib, (subLibSrcs,excluded))+          )+          (indexWithNeighbors subLibSrcDirs)+    subLibsExposed :: [FilePath] -> IO [(Library,ExposedLib)]+    subLibsExposed mainLibSrcs =+      mapM (\(subLib,(subLibSrcs,excluded)) -> do+               exposedMods <- getExposedModules (sourceExtensions ++ ppExts) subLibSrcs excluded+               exposedSigs <- getExposedModules hsigExtensions subLibSrcs excluded+               pure (subLib, ExposedLib exposedMods exposedSigs)+           )+           (subLibSrcDirsWithExcludedPaths mainLibSrcs)  -- | Since the @hs-source-dirs@ fields in a @.cabal@ file take a source tree -- path relative to the @.cabal@ file itself we need to make sure the current -- working directory in which to search for module detection is the directory in -- which the @.cabal@ file resides.-withCabalFileDirectory+withCabalFileDirectoryCwd   :: HasCallStack-  => IO a -- ^ The IO action that auto detects modules & signatures+  => Maybe FilePath -- ^ Absolute path to the directory containing a '.cabal' file, current directory if absent+  -> IO a -- ^ The IO action that auto detects modules & signatures   -> IO a-withCabalFileDirectory action = do-  cabalFilePath <- findPackageDesc "."+withCabalFileDirectoryCwd projectPathM action = do+  let pp = fromMaybe "." projectPathM+  cabalFilePath <- findPackageDesc pp   case cabalFilePath of     Left err -> error err-    Right _ -> withCurrentDirectory "." action+    Right _ -> withCurrentDirectory pp action  -- | Update the exposed modules and signatures of a 'Library'-updateLibrary :: ExposedLib -> Library -> Library-updateLibrary exposedLib =-  (L.exposedModules %~ (nub . (++) (exposedLibModules exposedLib)))-  . (L.signatures %~ (nub . (++) (exposedLibSignatures exposedLib)))+updateLibrary :: Library -> ExposedLib -> Library+updateLibrary lib exposedLib =+  lib & (L.exposedModules %~ (nub . (++) (exposedLibModules exposedLib)))+      . (L.signatures %~ (nub . (++) (exposedLibSignatures exposedLib)))  -- | Update the 'PackageDescription' of this package to include auto detected -- library modules. Also just to be nice fill in the 'Paths_...' module in -- 'otherModules' field of the library's 'BuildInfo'. updatePackageDescription :: HasCallStack => PackageDescription -> UserHooks -> IO PackageDescription updatePackageDescription pd uhs =-  withCabalFileDirectory $ do-    exposedLib <- getExposedLib (packageDescriptionToSubset pd) uhs-    let newMainLibrary =-         (L.libBuildInfo . L.otherModules %~ (nub . (++) [(autogenPathsModuleName pd)]))-         . updateLibrary exposedLib-    pure (pd { library = fmap newMainLibrary (library pd) })+  withCabalFileDirectoryCwd Nothing $ do+    (AllExposed exposedLib exposedSubLibs) <-+      getAllExposed (packageDescriptionToSubset pd) (map fst (hookedPreProcessors uhs))+    let newMainLibrary l =+          (updateLibrary l exposedLib) &+            (L.libBuildInfo . L.otherModules %~ (nub . (++) [(autogenPathsModuleName pd)]))+    pure (pd { library = fmap newMainLibrary (library pd)+             , subLibraries = map (uncurry updateLibrary) exposedSubLibs+             })  -- | Update the 'GenericPackageDescription' of this package so the library can -- be properly instantiated with Backpack signatures at configure time when the -- 'confHook' is run.-updateGenericPackageDescription :: HasCallStack => GenericPackageDescription -> UserHooks -> IO GenericPackageDescription-updateGenericPackageDescription gpd uhs =+updateGenericPackageDescription ::+  HasCallStack+  => Maybe FilePath -- ^ Absolute path of the directory which contains the '.cabal' file, in other words the root of the project+  -> GenericPackageDescription+  -> [String] -- ^ Custom preprocessor extensions+  -> IO GenericPackageDescription+updateGenericPackageDescription projectPath gpd ppExts =   let updateCondTreeLib exposedLib condLib =-        condLib { condTreeData = updateLibrary exposedLib (condTreeData condLib) }-  in withCabalFileDirectory $ do-      exposedLib <- getExposedLib (genericPackageDescriptionToSubset gpd) uhs+        condLib { condTreeData = updateLibrary (condTreeData condLib) exposedLib  }+  in withCabalFileDirectoryCwd projectPath $ do+      (AllExposed exposedLib exposedSubLibs) <-+        getAllExposed (genericPackageDescriptionToSubset gpd) ppExts       pure $-        gpd { condLibrary = fmap (updateCondTreeLib exposedLib) (condLibrary gpd) }+        gpd { condLibrary = fmap (updateCondTreeLib exposedLib) (condLibrary gpd)+            , condSubLibraries =+                map (\((unqualName,condSubLib),subLib) -> (unqualName,condSubLib { condTreeData = subLib }))+                    (zip (condSubLibraries gpd) (map (uncurry updateLibrary) exposedSubLibs))+            }  -- | The default name to use when generating an explicit Cabal file -- It defaults to @<package-name>-<package-version>-generated.cabal@@@ -304,7 +353,7 @@   -> ConfigFlags   -> IO LocalBuildInfo autoExposeConfHook userHooks writeGeneratedCabalM (gpd,hbi) cfs = do-  newGpd <- updateGenericPackageDescription gpd userHooks+  newGpd <- updateGenericPackageDescription (Just ".") gpd (map fst (hookedPreProcessors userHooks))   whenJust writeGeneratedCabalM     (\(WriteGeneratedCabal outputDir generatedCabalName) -> do         let f = outputDir </> (generatedCabalName newGpd)