cabal-helper 0.5.3.0 → 0.6.0.0
raw patch · 9 files changed
+274/−132 lines, 9 filesdep −data-defaultPVP ok
version bump matches the API change (PVP)
Dependencies removed: data-default
API changes (from Hackage documentation)
- Distribution.Helper: instance Default Programs
- Distribution.Helper: runQuery' :: Monad m => Programs -> FilePath -> FilePath -> Query m a -> m a
- Distribution.Helper: runQuery'' :: Monad m => (FilePath -> [String] -> String -> IO String) -> Programs -> FilePath -> FilePath -> Query m a -> m a
+ Distribution.Helper: data QueryEnv
+ Distribution.Helper: defaultPrograms :: Programs
+ Distribution.Helper: defaultQueryEnv :: FilePath -> FilePath -> QueryEnv
+ Distribution.Helper: pkgLicenses :: MonadIO m => Query m [(String, [(String, Version)])]
+ Distribution.Helper: qeCabalPkgDb :: QueryEnv -> Maybe FilePath
+ Distribution.Helper: qeCabalVer :: QueryEnv -> Maybe Version
+ Distribution.Helper: qeDistDir :: QueryEnv -> FilePath
+ Distribution.Helper: qePrograms :: QueryEnv -> Programs
+ Distribution.Helper: qeProjectDir :: QueryEnv -> FilePath
+ Distribution.Helper: qeReadProcess :: QueryEnv -> FilePath -> [String] -> String -> IO String
- Distribution.Helper: runQuery :: Monad m => FilePath -> FilePath -> Query m a -> m a
+ Distribution.Helper: runQuery :: Monad m => QueryEnv -> Query m a -> m a
Files
- CabalHelper/Common.hs +0/−14
- CabalHelper/Compile.hs +43/−36
- CabalHelper/Data.hs +1/−0
- CabalHelper/Licenses.hs +102/−0
- CabalHelper/Main.hs +23/−15
- CabalHelper/Types.hs +4/−1
- CabalHelper/Wrapper.hs +24/−10
- Distribution/Helper.hs +75/−53
- cabal-helper.cabal +2/−3
CabalHelper/Common.hs view
@@ -50,20 +50,6 @@ prog <- getProgName hPutStrLn stderr $ prog ++ ": " ++ str -align :: String -> String -> String -> String-align n an str = let- h:rest = lines str- [hm] = match n h- rest' = [ move (hm - rm) r | r <- rest, rm <- match an r]- in- unlines (h:rest')- where- match p str' = maybeToList $- fst <$> find ((p `isPrefixOf`) . snd) ([0..] `zip` tails str')- move i str' | i > 0 = replicate i ' ' ++ str'- move i str' = drop i str'-- -- | @getCabalConfigHeader "dist/setup-config"@ returns the cabal version and -- compiler version getCabalConfigHeader :: FilePath -> IO (Maybe (Version, (ByteString, Version)))
CabalHelper/Compile.hs view
@@ -46,19 +46,33 @@ import CabalHelper.Types import CabalHelper.Log +data Compile = Compile {+ compCabalHelperSourceDir :: FilePath,+ compCabalSourceDir :: Maybe FilePath,+ compPackageDb :: Maybe FilePath,+ compCabalVersion :: Version,+ compPackageDeps :: [String]+ }+ compileHelper :: Options -> Version -> FilePath -> FilePath -> IO (Either ExitCode FilePath) compileHelper opts cabalVer projdir distdir = withHelperSources $ \chdir -> do- run [ compileCabalSource chdir -- TODO: here ghc's caching fails and it always- -- recompiles, probably because we write the- -- sources to a tempdir and they always look- -- newer than the Cabal sources, not sure if we- -- can fix this- , Right <$> MaybeT (cachedExe cabalVer)- , compileSandbox chdir- , compileGlobal chdir- , cachedCabalPkg chdir- , MaybeT (Just <$> compilePrivatePkgDb chdir)- ]+ case cabalPkgDb opts of+ Nothing ->+ run [+ -- TODO: here ghc's caching fails and it always recompiles, probably+ -- because we write the sources to a tempdir and they always look+ -- newer than the Cabal sources, not sure if we can fix this+ compileCabalSource chdir+ , Right <$> MaybeT (cachedExe cabalVer)+ , compileSandbox chdir+ , compileGlobal chdir+ , cachedCabalPkg chdir+ , MaybeT (Just <$> compilePrivatePkgDb chdir)+ ]+ mdb ->+ run [ Right <$> MaybeT (cachedExe cabalVer)+ , liftIO $ compileWithPkg chdir mdb cabalVer+ ] where run actions = fromJust <$> runMaybeT (msum actions)@@ -95,7 +109,7 @@ case db_exists of False -> mzero True -> do- db <- liftIO $ cabalPkgDb opts cabalVer+ db <- liftIO $ getPrivateCabalPkgDb opts cabalVer vLog opts $ logMsg ++ "private package-db in " ++ db liftIO $ compileWithPkg chdir (Just db) cabalVer @@ -134,17 +148,9 @@ cabalPkgId v = "Cabal-" ++ showVersion v -data Compile = Compile {- cabalHelperSourceDir :: FilePath,- cabalSourceDir :: Maybe FilePath,- packageDb :: Maybe FilePath,- cabalVersion :: Version,- packageDeps :: [String]- }- compile :: FilePath -> Options -> Compile -> IO (Either ExitCode FilePath) compile distdir opts@Options {..} Compile {..} = do- cCabalSourceDir <- canonicalizePath `traverse` cabalSourceDir+ cCabalSourceDir <- canonicalizePath `traverse` compCabalSourceDir appdir <- appDataDir let outdir' = maybe appdir (const $ distdir </> "cabal-helper") cCabalSourceDir@@ -154,12 +160,12 @@ let exedir' = maybe outdir (const distdir) cCabalSourceDir createDirectoryIfMissing True exedir' exedir <- canonicalizePath exedir'- exe <- exePath' cabalVersion <$> canonicalizePath exedir+ exe <- exePath' compCabalVersion <$> canonicalizePath exedir vLog opts $ "outdir: " ++ outdir vLog opts $ "exedir: " ++ exedir - let Version (mj:mi:_) _ = cabalVersion+ let Version (mj:mi:_) _ = compCabalVersion let ghc_opts = concat [ [ "-outputdir", outdir@@ -168,12 +174,13 @@ , "-optP-DCABAL_MAJOR=" ++ show mj , "-optP-DCABAL_MINOR=" ++ show mi ],- maybeToList $ ("-package-conf="++) <$> packageDb,+ maybeToList $ ("-package-conf="++) <$> compPackageDb, map ("-i"++) $ nub $ ".":maybeToList cCabalSourceDir, if isNothing cCabalSourceDir then [ "-hide-all-packages" , "-package", "base"+ , "-package", "containers" , "-package", "directory" , "-package", "filepath" , "-package", "process"@@ -182,7 +189,7 @@ ] else [], - concatMap (\p -> ["-package", p]) packageDeps,+ concatMap (\p -> ["-package", p]) compPackageDeps, [ "--make", "CabalHelper/Main.hs" ] ] @@ -190,19 +197,19 @@ -- TODO: touch exe after, ghc doesn't do that if the input files didn't -- actually change- rv <- callProcessStderr' (Just cabalHelperSourceDir) ghcProgram ghc_opts+ rv <- callProcessStderr' (Just compCabalHelperSourceDir) ghcProgram ghc_opts return $ case rv of ExitSuccess -> Right exe e@(ExitFailure _) -> Left e exePath :: Version -> IO FilePath-exePath cabalVersion = do- exePath' cabalVersion <$> appDataDir+exePath compCabalVersion = do+ exePath' compCabalVersion <$> appDataDir exePath' :: Version-> FilePath -> FilePath-exePath' cabalVersion outdir =+exePath' compCabalVersion outdir = outdir </> "cabal-helper-" ++ showVersion version -- our ver- ++ "-Cabal-" ++ showVersion cabalVersion+ ++ "-Cabal-" ++ showVersion compCabalVersion callProcessStderr' :: Maybe FilePath -> FilePath -> [String] -> IO ExitCode callProcessStderr' mwd exe args = do@@ -303,8 +310,8 @@ sver = showVersion cabalVer cachedExe :: Version -> IO (Maybe FilePath)-cachedExe cabalVersion = do- exe <- exePath cabalVersion+cachedExe compCabalVersion = do+ exe <- exePath compCabalVersion exists <- doesFileExist exe return $ if exists then Just exe else Nothing @@ -322,7 +329,7 @@ cabalPkgDbExists :: Options -> Version -> IO Bool cabalPkgDbExists opts ver = do- db <- cabalPkgDb opts ver+ db <- getPrivateCabalPkgDb opts ver dexists <- doesDirectoryExist db case dexists of False -> return False@@ -348,13 +355,13 @@ createPkgDb :: Options -> Version -> IO FilePath createPkgDb opts@Options {..} ver = do- db <- cabalPkgDb opts ver+ db <- getPrivateCabalPkgDb opts ver exists <- doesDirectoryExist db when (not exists) $ callProcessStderr Nothing ghcPkgProgram ["init", db] return db -cabalPkgDb :: Options -> Version -> IO FilePath-cabalPkgDb opts ver = do+getPrivateCabalPkgDb :: Options -> Version -> IO FilePath+getPrivateCabalPkgDb opts ver = do appdir <- appDataDir ghcVer <- ghcVersion opts return $ appdir </> "Cabal-" ++ showVersion ver ++ "-db-" ++ showVersion ghcVer
CabalHelper/Data.hs view
@@ -41,5 +41,6 @@ [ ("Main.hs", $(LitE . StringL <$> runIO (UTF8.toString <$> BS.readFile "CabalHelper/Main.hs"))) , ("Common.hs", $(LitE . StringL <$> runIO (UTF8.toString <$> BS.readFile "CabalHelper/Common.hs"))) , ("Sandbox.hs", $(LitE . StringL <$> runIO (UTF8.toString <$> BS.readFile "CabalHelper/Sandbox.hs")))+ , ("Licenses.hs", $(LitE . StringL <$> runIO (UTF8.toString <$> BS.readFile "CabalHelper/Licenses.hs"))) , ("Types.hs", $(LitE . StringL <$> runIO (UTF8.toString <$> BS.readFile "CabalHelper/Types.hs"))) ]
+ CabalHelper/Licenses.hs view
@@ -0,0 +1,102 @@+{-# LANGUAGE CPP #-}+module CabalHelper.Licenses where++-- Copyright (c) 2014, Jasper Van der Jeugt <m@jaspervdj.be>++--------------------------------------------------------------------------------+import Control.Arrow ((***), (&&&))+import Control.Monad (forM_, unless)+import Data.List (foldl', sort)+import Data.Maybe (catMaybes)+import Data.Version (Version)+import Data.Set (Set)+import qualified Data.Set as Set+import Distribution.InstalledPackageInfo (InstalledPackageInfo)+import qualified Distribution.InstalledPackageInfo as InstalledPackageInfo+import qualified Distribution.License as Cabal+import qualified Distribution.Package as Cabal+import qualified Distribution.Simple.Configure as Cabal+import qualified Distribution.Simple.LocalBuildInfo as Cabal+import qualified Distribution.Simple.PackageIndex as Cabal+import qualified Distribution.Text as Cabal+import System.Directory (getDirectoryContents)+import System.Exit (exitFailure)+import System.FilePath (takeExtension)+import System.IO (hPutStrLn, stderr)++--------------------------------------------------------------------------------++#if CABAL_MAJOR == 1 && CABAL_MINOR > 22+type PackageIndex a = Cabal.PackageIndex (InstalledPackageInfo.InstalledPackageInfo)+#elif CABAL_MAJOR == 1 && CABAL_MINOR >= 22+type PackageIndex a = Cabal.PackageIndex (InstalledPackageInfo.InstalledPackageInfo_ a)+#else+type PackageIndex a = Cabal.PackageIndex+#endif++findTransitiveDependencies+ :: PackageIndex a+ -> Set Cabal.InstalledPackageId+ -> Set Cabal.InstalledPackageId+findTransitiveDependencies pkgIdx set0 = go Set.empty (Set.toList set0)+ where+ go set [] = set+ go set (q : queue)+ | q `Set.member` set = go set queue+ | otherwise =+ case Cabal.lookupInstalledPackageId pkgIdx q of+ Nothing ->+ -- Not found can mean that the package still needs to be+ -- installed (e.g. a component of the target cabal package).+ -- We can ignore those.+ go set queue+ Just ipi ->+ go (Set.insert q set)+ (InstalledPackageInfo.depends ipi ++ queue)+++--------------------------------------------------------------------------------+getDependencyInstalledPackageIds+ :: Cabal.LocalBuildInfo -> Set Cabal.InstalledPackageId+getDependencyInstalledPackageIds lbi =+ findTransitiveDependencies (Cabal.installedPkgs lbi) $+ Set.fromList $ map fst $ Cabal.externalPackageDeps lbi++--------------------------------------------------------------------------------+getDependencyInstalledPackageInfos+ :: Cabal.LocalBuildInfo -> [InstalledPackageInfo]+getDependencyInstalledPackageInfos lbi = catMaybes $+ map (Cabal.lookupInstalledPackageId pkgIdx) $+ Set.toList (getDependencyInstalledPackageIds lbi)+ where+ pkgIdx = Cabal.installedPkgs lbi+++--------------------------------------------------------------------------------+groupByLicense+ :: [InstalledPackageInfo]+ -> [(Cabal.License, [InstalledPackageInfo])]+groupByLicense = foldl'+ (\assoc ipi -> insert (InstalledPackageInfo.license ipi) ipi assoc) []+ where+ -- 'Cabal.License' doesn't have an 'Ord' instance so we need to use an+ -- association list instead of 'Map'. The number of licenses probably won't+ -- exceed 100 so I think we're alright.+ insert :: Eq k => k -> v -> [(k, [v])] -> [(k, [v])]+ insert k v [] = [(k, [v])]+ insert k v ((k', vs) : kvs)+ | k == k' = (k, v : vs) : kvs+ | otherwise = (k', vs) : insert k v kvs+++--------------------------------------------------------------------------------+displayDependencyLicenseList+ :: [(Cabal.License, [InstalledPackageInfo])]+ -> [(String, [(String, Version)])]+displayDependencyLicenseList =+ map (Cabal.display *** map (getName &&& getVersion))+ where+ getName =+ Cabal.display . Cabal.pkgName . InstalledPackageInfo.sourcePackageId+ getVersion =+ Cabal.pkgVersion . InstalledPackageInfo.sourcePackageId
CabalHelper/Main.hs view
@@ -79,28 +79,31 @@ import System.IO.Unsafe (unsafeInterleaveIO, unsafePerformIO) import Text.Printf +import CabalHelper.Licenses import CabalHelper.Sandbox import CabalHelper.Common import CabalHelper.Types hiding (Options(..)) usage = do prog <- getProgName- hPutStr stderr $ align "(" "|" ("Usage: " ++ prog ++ " " ++ usageMsg)+ hPutStr stderr $ "Usage: " ++ prog ++ " " ++ usageMsg where usageMsg = ""- ++"DIST_DIR ( version\n"- ++" | print-lbi [--human]\n"- ++" | write-autogen-files\n"- ++" | compiler-version\n"- ++" | ghc-options [--with-inplace]\n"- ++" | ghc-src-options [--with-inplace]\n"- ++" | ghc-pkg-options [--with-inplace]\n"- ++" | ghc-merged-pkg-options [--with-inplace]\n"- ++" | ghc-lang-options [--with-inplace]\n"- ++" | package-db-stack\n"- ++" | entrypoints\n"- ++" | source-dirs\n"- ++" ) ...\n"+ ++"PROJ_DIR DIST_DIR [--with-* ...] (\n"+ ++" version\n"+ ++" | print-lbi [--human]\n"+ ++" | write-autogen-files\n"+ ++" | compiler-version\n"+ ++" | ghc-options [--with-inplace]\n"+ ++" | ghc-src-options [--with-inplace]\n"+ ++" | ghc-pkg-options [--with-inplace]\n"+ ++" | ghc-merged-pkg-options [--with-inplace]\n"+ ++" | ghc-lang-options [--with-inplace]\n"+ ++" | package-db-stack\n"+ ++" | entrypoints\n"+ ++" | source-dirs\n"+ ++" | licenses\n"+ ++" ) ...\n" commands :: [String] commands = [ "print-bli"@@ -112,7 +115,8 @@ , "ghc-lang-options" , "package-db-stack" , "entrypoints"- , "source-dirs"]+ , "source-dirs"+ , "licenses"] main :: IO () main = do@@ -237,6 +241,10 @@ "source-dirs":[] -> do res <- componentsMap lbi v distdir $$ \_ _ bi -> return $ hsSourceDirs bi return $ Just $ ChResponseCompList (res ++ [(ChSetupHsName, [])])++ "licenses":[] -> do+ return $ Just $ ChResponseLicenses $+ displayDependencyLicenseList $ groupByLicense $ getDependencyInstalledPackageInfos lbi "print-lbi":flags -> case flags of
CabalHelper/Types.hs view
@@ -37,6 +37,7 @@ | ChResponsePkgDbs [ChPkgDb] | ChResponseLbi String | ChResponseVersion String Version+ | ChResponseLicenses [(String, [(String, Version)])] deriving (Eq, Ord, Read, Show, Generic) data ChEntrypoint = ChSetupEntrypoint -- ^ Almost like 'ChExeEntrypoint' but@@ -61,7 +62,9 @@ , ghcProgram :: FilePath , ghcPkgProgram :: FilePath , cabalProgram :: FilePath+ , cabalVersion :: Maybe Version+ , cabalPkgDb :: Maybe FilePath } defaultOptions :: Options-defaultOptions = Options False "ghc" "ghc-pkg" "cabal"+defaultOptions = Options False "ghc" "ghc-pkg" "cabal" Nothing Nothing
CabalHelper/Wrapper.hs view
@@ -45,7 +45,7 @@ usage :: IO () usage = do prog <- getProgName- hPutStr stderr $ align "(" "|" ("Usage: " ++ prog ++ " " ++ usageMsg)+ hPutStr stderr $ "Usage: " ++ prog ++ " " ++ usageMsg where usageMsg = "\ \( print-appdatadir\n\@@ -54,6 +54,8 @@ \ [--with-ghc=GHC_PATH]\n\ \ [--with-ghc-pkg=GHC_PKG_PATH]\n\ \ [--with-cabal=CABAL_PATH]\n\+\ [--with-cabal-version=VERSION]\n\+\ [--with-cabal-pkg-db=PKG_DB]\n\ \ PROJ_DIR DIST_DIR ( print-exe | [CABAL_HELPER_ARGS...] ) )\n" globalArgSpec :: [OptDescr (Options -> Options)]@@ -69,6 +71,13 @@ , option "" ["with-cabal"] "cabal-install executable to use" $ reqArg "PROG" $ \p o -> o { cabalProgram = p }++ , option "" ["with-cabal-version"] "Cabal library version to use" $+ reqArg "VERSION" $ \p o -> o { cabalVersion = Just $ parseVer p }++ , option "" ["with-cabal-pkg-db"] "package database to look for Cabal library in" $+ reqArg "PKG_DB" $ \p o -> o { cabalPkgDb = Just p }+ ] where option :: [Char] -> [String] -> String -> ArgDescr a -> OptDescr a@@ -116,13 +125,18 @@ \- Check first line of: %s\n\ \- Maybe try: $ cabal configure" cfgf Just (hdrCabalVersion, _) -> do- eexe <- compileHelper opts hdrCabalVersion projdir distdir- case eexe of- Left e -> exitWith e- Right exe ->- case args' of- "print-exe":_ -> putStrLn exe- _ -> do- (_,_,_,h) <- createProcess $ proc exe args- exitWith =<< waitForProcess h+ case cabalVersion opts of+ Just ver | hdrCabalVersion /= ver -> panic $ printf "\+\Cabal version %s was requested setup configuration was\n\+\written by version %s" (showVersion ver) (showVersion hdrCabalVersion)+ _ -> do+ eexe <- compileHelper opts hdrCabalVersion projdir distdir+ case eexe of+ Left e -> exitWith e+ Right exe ->+ case args' of+ "print-exe":_ -> putStrLn exe+ _ -> do+ (_,_,_,h) <- createProcess $ proc exe args+ exitWith =<< waitForProcess h _ -> error "invalid command line"
Distribution/Helper.hs view
@@ -14,17 +14,24 @@ -- You should have received a copy of the GNU Affero General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. -{-# LANGUAGE CPP, FlexibleContexts, ConstraintKinds #-}+{-# LANGUAGE CPP, RecordWildCards, FlexibleContexts, ConstraintKinds #-} {-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable, DeriveGeneric #-} module Distribution.Helper ( Programs(..)+ , defaultPrograms+ , QueryEnv+ , qeReadProcess+ , qePrograms+ , qeProjectDir+ , qeDistDir+ , qeCabalPkgDb+ , qeCabalVer+ , defaultQueryEnv -- * Running Queries , Query , runQuery- , runQuery'- , runQuery'' -- * Queries against Cabal\'s on disk state @@ -36,6 +43,7 @@ , ghcPkgOptions , ghcMergedPkgOptions , ghcLangOptions+ , pkgLicenses -- * Result types , ChModuleName(..)@@ -67,7 +75,6 @@ import Control.Exception as E import Data.Char import Data.List-import Data.Default import Data.Version import Data.Typeable import Distribution.Simple.BuildPaths (exeExtension)@@ -91,9 +98,46 @@ ghcPkgProgram :: FilePath } deriving (Eq, Ord, Show, Read, Generic, Typeable) -instance Default Programs where- def = Programs "cabal" "ghc" "ghc-pkg"+defaultPrograms :: Programs+defaultPrograms = Programs "cabal" "ghc" "ghc-pkg" +data QueryEnv = QueryEnv {+ -- | How to start the cabal-helper process. Useful if you need to+ -- capture stderr output from the helper.+ qeReadProcess :: FilePath -> [String] -> String -> IO String,++ qePrograms :: Programs,++ -- | Path to project directory, i.e. the one containing the+ -- @project.cabal@ file+ qeProjectDir :: FilePath,++ -- | Path to the @dist/@ directory+ qeDistDir :: FilePath,++ -- | Where to look for the Cabal library when linking the helper+ qeCabalPkgDb :: Maybe FilePath,++ -- | If @dist/setup-config@ wasn\'t written by this version of Cabal throw+ -- an error+ qeCabalVer :: Maybe Version+ }++defaultQueryEnv :: FilePath+ -- ^ Path to project directory, i.e. the one containing the+ -- @project.cabal@ file+ -> FilePath+ -- ^ Path to the @dist/@ directory+ -> QueryEnv+defaultQueryEnv projdir distdir = QueryEnv {+ qeReadProcess = readProcess+ , qePrograms = defaultPrograms+ , qeProjectDir = projdir+ , qeDistDir = distdir+ , qeCabalPkgDb = Nothing+ , qeCabalVer = Nothing+ }+ data SomeLocalBuildInfo = SomeLocalBuildInfo { slbiPackageDbStack :: [ChPkgDb], slbiEntrypoints :: [(ChComponentName, ChEntrypoint)],@@ -102,7 +146,8 @@ slbiGhcSrcOptions :: [(ChComponentName, [String])], slbiGhcPkgOptions :: [(ChComponentName, [String])], slbiGhcMergedPkgOptions :: [String],- slbiGhcLangOptions :: [(ChComponentName, [String])]+ slbiGhcLangOptions :: [(ChComponentName, [String])],+ slbiPkgLicenses :: [(String, [(String, Version)])] } deriving (Eq, Ord, Read, Show) -- | Caches helper executable result so it doesn't have to be run more than once@@ -112,54 +157,20 @@ (ReaderT QueryEnv m) a } deriving (Functor, Applicative, Monad, MonadIO) -data QueryEnv = QueryEnv {- _qeReadProcess :: FilePath -> [String] -> String -> IO String,- _qeProgs :: Programs,- _qeProjectDir :: FilePath,- _qeDistDir :: FilePath- }- type MonadQuery m = ( MonadIO m , MonadState (Maybe SomeLocalBuildInfo) m , MonadReader QueryEnv m) -run :: Monad m- => QueryEnv -> Maybe SomeLocalBuildInfo -> Query m a -> m a+run :: Monad m => QueryEnv -> Maybe SomeLocalBuildInfo -> Query m a -> m a run e s action = flip runReaderT e (flip evalStateT s (unQuery action)) -- | @runQuery query distdir@. Run a 'Query'. @distdir@ is where Cabal's -- @setup-config@ file is located. runQuery :: Monad m- => FilePath -- ^ Path to project directory, i.e. the one containing the- -- @project.cabal@ file- -> FilePath -- ^ Path to @dist/@- -> Query m a- -> m a-runQuery pd dd action = run (QueryEnv readProcess def pd dd) Nothing action--runQuery' :: Monad m- => Programs- -> FilePath -- ^ Path to project directory, i.e. the one containing the- -- @project.cabal@ file- -> FilePath -- ^ Path to @dist/@- -> Query m a- -> m a-runQuery' progs pd dd action =- run (QueryEnv readProcess progs pd dd) Nothing action--runQuery'' :: Monad m- => (FilePath -> [String] -> String -> IO String)- -- ^ How to start the cabal-helper process. Useful if you need to- -- capture stderr output from the helper.- -> Programs- -> FilePath -- ^ Path to project directory, i.e. the one containing the- -- @project.cabal@ file- -> FilePath -- ^ Path to @dist/@+ => QueryEnv -> Query m a -> m a-runQuery'' readProc progs pd dd action =- run (QueryEnv readProc progs pd dd) Nothing action-+runQuery qe action = run qe Nothing action getSlbi :: MonadQuery m => m SomeLocalBuildInfo getSlbi = do@@ -198,6 +209,9 @@ -- | Only language related options, i.e. @-XSomeExtension@ ghcLangOptions :: MonadIO m => Query m [(ChComponentName, [String])] +-- | Get the licenses of the packages the current project is linking against.+pkgLicenses :: MonadIO m => Query m [(String, [(String, Version)])]+ packageDbStack = Query $ slbiPackageDbStack `liftM` getSlbi entrypoints = Query $ slbiEntrypoints `liftM` getSlbi sourceDirs = Query $ slbiSourceDirs `liftM` getSlbi@@ -206,6 +220,7 @@ ghcPkgOptions = Query $ slbiGhcPkgOptions `liftM` getSlbi ghcMergedPkgOptions = Query $ slbiGhcMergedPkgOptions `liftM` getSlbi ghcLangOptions = Query $ slbiGhcLangOptions `liftM` getSlbi+pkgLicenses = Query $ slbiPkgLicenses `liftM` getSlbi -- | Run @cabal configure@ reconfigure :: MonadIO m@@ -218,7 +233,7 @@ [ "--with-ghc=" ++ ghcProgram progs ] -- Only pass ghc-pkg if it was actually set otherwise we -- might break cabal's guessing logic- ++ if ghcPkgProgram progs /= ghcPkgProgram def+ ++ if ghcPkgProgram progs /= "ghc-pkg" then [ "--with-ghc-pkg=" ++ ghcPkgProgram progs ] else [] ++ cabalOpts@@ -226,13 +241,17 @@ return () getSomeConfigState :: MonadQuery m => m SomeLocalBuildInfo-getSomeConfigState = ask >>= \(QueryEnv readProc progs projdir distdir) -> do- let progArgs = [ "--with-ghc=" ++ ghcProgram progs+getSomeConfigState = ask >>= \QueryEnv {..} -> do+ let progs = qePrograms+ projdir = qeProjectDir+ distdir = qeDistDir++ progArgs = [ "--with-ghc=" ++ ghcProgram progs , "--with-ghc-pkg=" ++ ghcPkgProgram progs , "--with-cabal=" ++ cabalProgram progs ] - let args = [ "package-db-stack"+ args = [ "package-db-stack" , "entrypoints" , "source-dirs" , "ghc-options"@@ -240,14 +259,15 @@ , "ghc-pkg-options" , "ghc-merged-pkg-options" , "ghc-lang-options"- ] ++ progArgs+ , "licenses"+ ] res <- liftIO $ do exe <- findLibexecExe "cabal-helper-wrapper"- out <- readProc exe (projdir:distdir:args) ""+ out <- qeReadProcess exe (progArgs ++ projdir:distdir:args) "" evaluate (read out) `E.catch` \(SomeException _) -> error $ concat ["getSomeConfigState", ": ", exe, " "- , intercalate " " (map show $ distdir:args)+ , intercalate " " (map show $ progArgs ++ projdir:distdir:args) , " (read failed)"] let [ Just (ChResponsePkgDbs pkgDbs),@@ -257,10 +277,12 @@ Just (ChResponseCompList ghcSrcOpts), Just (ChResponseCompList ghcPkgOpts), Just (ChResponseList ghcMergedPkgOpts),- Just (ChResponseCompList ghcLangOpts) ] = res+ Just (ChResponseCompList ghcLangOpts),+ Just (ChResponseLicenses pkgLics)+ ] = res return $ SomeLocalBuildInfo- pkgDbs eps srcDirs ghcOpts ghcSrcOpts ghcPkgOpts ghcMergedPkgOpts ghcLangOpts+ pkgDbs eps srcDirs ghcOpts ghcSrcOpts ghcPkgOpts ghcMergedPkgOpts ghcLangOpts pkgLics -- | Make sure the appropriate helper executable for the given project is -- installed and ready to run queries.
cabal-helper.cabal view
@@ -1,5 +1,5 @@ name: cabal-helper-version: 0.5.3.0+version: 0.6.0.0 synopsis: Simple interface to some of Cabal's configuration state used by ghc-mod description: @cabal-helper@ provides a library which wraps the internal use of@@ -35,6 +35,7 @@ build-type: Custom cabal-version: >=1.10 extra-source-files: CabalHelper/Main.hs+ CabalHelper/Licenses.hs source-repository head type: git@@ -49,7 +50,6 @@ GHC-Options: -Wall Build-Depends: base >= 4.5 && < 5 , Cabal >= 1.14 && < 1.23- , data-default , directory , filepath , transformers@@ -93,7 +93,6 @@ , extra , unix , Cabal >= 1.14 && < 1.23- , data-default , directory , filepath , transformers