diff options
-rw-r--r-- | lib/Distribution/Helper.hs | 22 | ||||
-rw-r--r-- | src/CabalHelper/Compiletime/Types.hs | 120 |
2 files changed, 108 insertions, 34 deletions
diff --git a/lib/Distribution/Helper.hs b/lib/Distribution/Helper.hs index b72fd2a..c290d41 100644 --- a/lib/Distribution/Helper.hs +++ b/lib/Distribution/Helper.hs @@ -46,6 +46,7 @@ module Distribution.Helper ( -- ** Unit queries , Unit -- abstract , uComponentName + , uPackageDir , UnitId -- abstract , UnitInfo(..) , unitInfo @@ -80,7 +81,7 @@ module Distribution.Helper ( , CompPrograms(..) , defaultCompPrograms - -- * Result types + -- * Query result types , ChComponentInfo(..) , ChComponentName(..) , ChLibraryName(..) @@ -92,16 +93,15 @@ module Distribution.Helper ( -- * General information , Distribution.Helper.buildPlatform - -- * Stuff that cabal-install really should export + -- * Legacy v1-build helpers , Distribution.Helper.getSandboxPkgDb - -- * Managing @dist/@ + -- * Stateful helper actions , prepare , writeAutogenFiles ) where import Cabal.Plan hiding (Unit, UnitId, uDistDir) -import Control.Arrow (first) import Control.Applicative import Control.Monad import Control.Monad.Trans.Maybe @@ -168,8 +168,8 @@ import Distribution.Simple.GHC as GHC (configure) -- accessor of 'QueryEnv' for details. --- | A lazy, cached, query against a package's Cabal configuration. Use --- 'runQuery' to execute it. +-- | A query against a package's Cabal configuration. Use 'runQuery' to +-- execute it. newtype Query pt a = Query { runQuery :: QueryEnv pt -> IO a -- ^ @runQuery env query@. Run a 'Query' under a given 'QueryEnv. @@ -560,13 +560,21 @@ invokeHelper -- | Make sure the appropriate helper executable for the given project is -- installed and ready to run queries. +-- +-- The idea is you can run this at a convinient time instead of having the +-- helper compilation happen during a time-sensitive user +-- interaction. @caba-helper@ will however do this automatically as needed +-- if you don't. prepare :: QueryEnv pt -> IO () prepare qe = do proj_info <- getProjInfo qe void $ getHelper proj_info qe --- | Create @cabal_macros.h@ and @Paths_\<pkg\>@ possibly other generated files +-- | Create @cabal_macros.h@, @Paths_\<pkg\>.hs@ and other generated files -- in the usual place. See 'Distribution.Simple.Build.initialBuildSteps'. +-- +-- This is usually only needed on the first load of a unit or after the +-- cabal file changes. writeAutogenFiles :: Unit pt -> Query pt () writeAutogenFiles unit = Query $ \qe -> do proj_info <- getProjInfo qe diff --git a/src/CabalHelper/Compiletime/Types.hs b/src/CabalHelper/Compiletime/Types.hs index edbcd46..cded136 100644 --- a/src/CabalHelper/Compiletime/Types.hs +++ b/src/CabalHelper/Compiletime/Types.hs @@ -42,13 +42,21 @@ import Data.List.NonEmpty (NonEmpty) import Data.Map.Strict (Map) --import qualified Data.Map.Strict as Strict --- | The kind of project being managed by a 'QueryEnv' (pun intended). +-- | The kind of project being managed by a 'QueryEnv' (pun intended). Used +-- as a phantom-type variable throughout to make the project type being +-- passed into various functions correspond to the correct implementation. data ProjType - = V1 -- ^ @cabal v1-build@ project, see 'DistDirV1' - | V2 -- ^ @cabal v2-build@ project, see 'DistDirV2' + = V1 -- ^ @cabal v1-build@ project. + | V2 -- ^ @cabal v2-build@ project. | Stack -- ^ @stack@ project. deriving (Eq, Ord, Show, Read) +-- | A "singleton" datatype for 'ProjType' which allows us to establish a +-- correspondence between a runtime representation of 'ProjType' to the +-- compile-time value at the type level. +-- +-- If you just want to know the runtime 'ProjType' use 'demoteSProjType' to +-- convert to that. data SProjType pt where SCabal :: !(SCabalProjType pt) -> SProjType pt SStack :: SProjType 'Stack @@ -69,28 +77,81 @@ demoteSProjType (SCabal SCV1) = V1 demoteSProjType (SCabal SCV2) = V2 demoteSProjType SStack = Stack --- | Location of project sources. The project type of a given directory can be --- determined by trying to access a set of marker files. See below. +-- | Location of a project context. Usually a project's top-level source +-- code directory or a project type specific config file. +-- +-- To find any recognized default project contexts in a given directory +-- use 'Distribution.Helper.Discover.findProjects'. +-- +-- Build tools usually allow the user to specify the location of their +-- project config files manually, so we also support passing this path here +-- with the @*File@ constructors. +-- +-- === Correspondence with Project Source Directory +-- +-- Note that the project's source directory does not necessarily correspond +-- to the directory containing the project config file, though in some +-- cases it does. +-- +-- For example cabal-V2 allows the @cabal.project@ file to be positively +-- anywhere in the filesystem when specified via the @--cabal-project@ +-- command-line flag, corresponding to the 'ProjLocV2File' constructor +-- here. This config file can then refer to package directories with +-- absolute paths in the @packages:@ declaration. +-- +-- Hence it isn't actually possible to find the whole project's toplevel +-- source directory given just a 'ProjLoc'. However the packages within a +-- project have a well defined source directory. +-- +-- Unfortunately we do not expose the concept of a "package" in the API to +-- abstract the differences between the project types. Instead each 'Unit' +-- (which is conceptually part of a "package") carries the corresponding +-- package source directory in 'uPackageDir'. Together with a 'Unit' query +-- such as 'projectUnits' you can thus get the source directory for each +-- unit. +-- +-- If you need to present this in a per-package view rather than a per-unit +-- view you should be able to use the source directory as a key to +-- determine which units to group into a package. data ProjLoc (pt :: ProjType) where - -- | A @cabal v1-build@ project directory can be identified by one file - -- ending in @.cabal@ existing in the directory. More than one such files - -- existing is a user error. Note: For this project type the concepts of - -- project and package coincide. + -- | A fully specified @cabal v1-build@ project context. Here you can + -- specify both the path to the @.cabal@ file and the source directory + -- of the package. The cabal file path corresponds to the + -- @--cabal-file=PATH@ flag on the @cabal@ command line. + -- + -- Note that More than one such files existing in a package directory + -- is a user error and cabal might still complain about that but we + -- won't. + -- + -- Also note that for this project type the concepts of project and + -- package coincide. ProjLocV1CabalFile :: { plCabalFile :: !FilePath, plPackageDir :: !FilePath } -> ProjLoc 'V1 - -- | A @cabal v1-build@ project directory. Same as 'ProjLocV1CabalFile' but - -- will search for the cabal file for you. If more than one @.cabal@ file - -- exists it will shamelessly throw an obscure exception. + -- | A @cabal v1-build@ project context. Essentially the same as + -- 'ProjLocV1CabalFile' but this will dynamically search for the cabal + -- file for you as cabal-install does by default. + -- + -- If more than one @.cabal@ file exists in the given directory we will + -- shamelessly throw a obscure exception when using this in the API so + -- prefer 'ProjLocV1CabalFile' if you don't want that to happen. This + -- mainly exists for easy upgrading from the @cabal-helper-0.8@ series. ProjLocV1Dir :: { plPackageDir :: !FilePath } -> ProjLoc 'V1 - -- | A @cabal v2-build@ project\'s marker file is called - -- @cabal.project@. This configuration file points to the packages that make - -- up this project. + -- | A @cabal v2-build@ project context. The path to the + -- @cabal.project@ file, though you can call it whatever you like. This + -- configuration file then points to the packages that make up this + -- project. This corresponds to the @--cabal-project=PATH@ flag on the + -- @cabal@ command line. ProjLocV2File :: { plCabalProjectFile :: !FilePath } -> ProjLoc 'V2 + + -- | This is equivalent to 'ProjLocV2File' but using the default + -- @cabal.project@ file name. ProjLocV2Dir :: { plV2Dir :: !FilePath } -> ProjLoc 'V2 - -- | A @stack@ project\'s marker file is called @stack.yaml@. This - -- configuration file points to the packages that make up this project. + -- | A @stack@ project context. Specify the path to the @stack.yaml@ + -- file here. This configuration file then points to the packages that + -- make up this project. Corresponds to @stack@'s @--stack-yaml=PATH@ + -- command line flag if different from the default name, @stack.yaml@. ProjLocStackYaml :: { plStackYaml :: !FilePath } -> ProjLoc 'Stack deriving instance Show (ProjLoc pt) @@ -107,13 +168,13 @@ projTypeOfProjLoc ProjLocV2Dir{} = SCabal SCV2 projTypeOfProjLoc ProjLocStackYaml{} = SStack -- | A build directory for a certain project type. The @pt@ type variable --- must match the value of 'ProjLoc'. This is enforced by the type system --- so you can't get this wrong :) +-- must be compatible with the 'ProjLoc' used. This is enforced by the type +-- system so you can't get this wrong. data DistDir (pt :: ProjType) where -- | A build-directory for cabal, aka. dist-dir in Cabal -- terminology. 'SCabalProjType' specifies whether we should use -- /v2-build/ or /v1-build/. This choice must correspond to - -- 'ProjLoc'\'s project type. + -- 'ProjLoc' \'s project type. DistDirCabal :: !(SCabalProjType pt) -> !FilePath -> DistDir pt -- | A build-directory for stack, aka. /work-dir/. Optionally override @@ -133,7 +194,7 @@ projTypeOfDistDir DistDirStack{} = SStack -- Say you have: -- -- @ --- {-# LANGUAGE DataKinds, GADTS #-} +-- {-\# LANGUAGE DataKinds, GADTS \#-} -- data K = A | B | ... -- data Q k where -- QA :: ... -> Q 'A @@ -209,13 +270,18 @@ data QueryCache pt = QueryCache newtype DistDirLib = DistDirLib FilePath deriving (Eq, Ord, Read, Show) --- | A 'Unit' is used as reference to a set of components (exes, libs, tests --- etc.) which are managed by an certain instance of the Cabal build system. We --- may get information on the components in a unit by retriving the --- corresponding 'UnitInfo'. +-- | A 'Unit' is essentially a "build target". It is used to refer to a set +-- of components (exes, libs, tests etc.) which are managed by a certain +-- instance of the Cabal build-system[1]. We may get information on the +-- components in a unit by retriving the corresponding 'UnitInfo'. +-- +-- \[1]: No I'm not talking about the cabal-install /build-tool/, I'm +-- talking about the Cabal /build-system/. Note the distinction. Both +-- cabal-install and Stack use the Cabal build-system (aka @lib:Cabal@) +-- underneath. -- --- Note that a 'Unit' value is only valid within the 'QueryEnv' context it was --- created in. However this is not enforced in the API. +-- Note that a 'Unit' value is only valid within the 'QueryEnv' context it +-- was created in. However this is not enforced by the API. data Unit pt = Unit { uUnitId :: !UnitId , uPackageDir :: !FilePath |