Skip to content

Commit b5c7050

Browse files
committed
Add pre and post build hooks
Run a program (named "preBuildHook") before doing a package build and another program (named "postBuildHook") after the package is built. The exit code from the pre-build hook is passed to the post-build hook. These programs are project local and need to be in the `cabalHooks` directory which is in the same directory as the `cabal.project` file. Co-authored: Moritz Angermann <[email protected]>
1 parent 214acd8 commit b5c7050

File tree

4 files changed

+107
-1
lines changed

4 files changed

+107
-1
lines changed

cabal-install/src/Distribution/Client/ProjectBuilding/UnpackedPackage.hs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ import qualified Data.ByteString.Lazy.Char8 as LBS.Char8
100100
import qualified Data.List.NonEmpty as NE
101101

102102
import Control.Exception (ErrorCall, Handler (..), SomeAsyncException, assert, catches)
103-
import System.Directory (canonicalizePath, createDirectoryIfMissing, doesDirectoryExist, doesFileExist, removeFile)
103+
import System.Directory (canonicalizePath, createDirectoryIfMissing, doesDirectoryExist, doesFileExist, getCurrentDirectory, removeFile)
104104
import System.FilePath (dropDrive, normalise, takeDirectory, (<.>), (</>))
105105
import System.IO (Handle, IOMode (AppendMode), withFile)
106106
import System.Semaphore (SemaphoreName (..))
@@ -679,7 +679,38 @@ buildAndInstallUnpackedPackage
679679
runConfigure
680680
PBBuildPhase{runBuild} -> do
681681
noticeProgress ProgressBuilding
682+
hooksDir <- (</> "cabalHooks") <$> getCurrentDirectory
683+
-- run preBuildHook. If it returns with 0, we assume the build was
684+
-- successful. If not, run the build.
685+
preCode <-
686+
rawSystemExitCode
687+
verbosity
688+
(Just srcdir)
689+
(hooksDir </> "preBuildHook")
690+
[ (unUnitId $ installedUnitId rpkg)
691+
, (getSymbolicPath srcdir)
692+
, (getSymbolicPath builddir)
693+
]
694+
Nothing
695+
`catchIO` (\_ -> pure (ExitFailure 10))
696+
-- Regardless of whether the preBuildHook exists or not, or whether it returned an
697+
-- error or not, we want to run the build command.
698+
-- If the preBuildHook downloads a cached version of the build products, the following
699+
-- should be a NOOP.
682700
runBuild
701+
-- not sure, if we want to care about a failed postBuildHook?
702+
void $
703+
rawSystemExitCode
704+
verbosity
705+
(Just srcdir)
706+
(hooksDir </> "postBuildHook")
707+
[ (unUnitId $ installedUnitId rpkg)
708+
, (getSymbolicPath srcdir)
709+
, (getSymbolicPath builddir)
710+
, show preCode
711+
]
712+
Nothing
713+
`catchIO` (\_ -> pure (ExitFailure 10))
683714
PBHaddockPhase{runHaddock} -> do
684715
noticeProgress ProgressHaddock
685716
runHaddock

changelog.d/pr-9899

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
synopsis: Add pre and post build hooks
2+
packages: cabal-install
3+
prs: #9899
4+
issues: #9892
5+
significance: significant
6+
7+
description: {
8+
9+
- Run a program (named "preBuildHook") before doing a package build and another program
10+
(named "postBuildHook") after the package is built.
11+
- These programs are project local and need to be in the `cabalHooks` directory which is
12+
in the same directory as the `cabal.project` file.
13+
- The absence of these programs will be ignored.
14+
}

doc/build-hooks.rst

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
Build Hooks
2+
===========
3+
4+
Build hooks are programs that are run before (pre-build hook) and
5+
after (post-build hook) a package (including package dependencies)
6+
is built. The hooks are completely generic and can even be absent
7+
(their absence is ignored). Regardless of the return code of the
8+
pre-build hook, the normal build is executed. In the case where
9+
the pre-build hook provides a pre-built version of what the build
10+
step would provide, the build step is still run, but should be
11+
little more than a NOOP.
12+
13+
Build hooks are project local rather than global to the user
14+
because a single user may want to use one set of hooks in one
15+
project and another set of hoos (or even none at all) for another
16+
project.
17+
18+
19+
Possible Use Cases
20+
------------------
21+
22+
Possible use cases include:
23+
24+
* Fine grained benchmarking of individual package build times.
25+
* Build product caching.
26+
27+
28+
Location of Hook Files
29+
----------------------
30+
31+
The two hook files are `cabalHooks/preBuildHook` and
32+
`cabalHooks/postBuildHook` where the `cabalHooks` directory is in
33+
the same directory as the `cabal.project` file. On UNIX style
34+
systems, these hooks need to be marked as user executable programs.
35+
36+
37+
Hook Parameters Exit Codes
38+
--------------------------
39+
40+
The pre-build hook is passed three parameters; the unit id (from cabal),
41+
the source directory and the build directory. The post-build hook is
42+
passed the same three parameters, plus the exit code of the pre-build
43+
hook.
44+
45+
The exit codes for the two hooks are ignored by cabal apart from cabal
46+
capturing the exit code for the pre-build hook and passing it to the
47+
post-build hook.
48+
49+
50+
Security Considerations
51+
-----------------------
52+
53+
These build hooks are generic executable programs. They can potentially
54+
be malicious. For example, one might clone a Haskell project from
55+
say Github, that includes malicious build hooks so that when the user runs
56+
`cabal build all` these hooks will be run as the user. The most obvious
57+
malicious behaviour would be to delete all the user's files.
58+
59+
For this reason, it is highly advisable to check for the existence
60+
of and the contents of any build hook files.

doc/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Welcome to the Cabal User Guide
1818
how-to-run-in-windows
1919
how-to-use-backpack
2020
how-to-report-bugs
21+
build-hooks
2122

2223
.. toctree::
2324
:caption: Cabal Reference

0 commit comments

Comments
 (0)