1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
-----------------------------------------------------------------------------
-- |
-- Module : Hadrian.Package
-- Copyright : (c) Andrey Mokhov 2014-2017
-- License : MIT (see the file LICENSE)
-- Maintainer : andrey.mokhov@gmail.com
-- Stability : experimental
--
-- A /package/ is a collection of files. We currently only support C and Haskell
-- packages and treat a package as either a library or a program. The latter is
-- a gross oversimplification as, for example, Haskell packages can be both.
-- This works for now, but should be improved in future.
-----------------------------------------------------------------------------
module Hadrian.Package (
-- * Data types
Package (..), PackageName, PackageType, PackageLocation(..),
-- * Construction and properties
library, program, external, dummyPackage
, isLibrary, isProgram,
Plugin(..), PluginArgs(..), addPlugin
) where
import Development.Shake.Classes
import Development.Shake
import GHC.Generics
-- TODO: Make PackageType more precise.
-- See https://github.com/snowleopard/hadrian/issues/12.
data PackageType = Library | Program deriving (Eq, Generic, Ord, Show)
data PackageLocation =
Internal FilePath -- ^ Path to the file contents relative to
-- root directory.
| External String -- ^ Version string to fetch package from Hackage.
deriving (Eq, Generic, Ord, Show)
type PackageName = String
-- TODO: Consider turning Package into a GADT indexed with language and type.
data Package = Package {
-- | The package type. 'Library' and 'Program' packages are supported.
pkgType :: PackageType,
-- | The package name. We assume that all packages have different names,
-- hence two packages with the same name are considered equal.
pkgName :: PackageName,
-- | The path to the package source code relative to the root of the build
-- system. For example, @libraries/Cabal/Cabal@ and @ghc@ are paths to the
-- @Cabal@ and @ghc-bin@ packages in GHC.
pkgLocation :: PackageLocation,
-- | Plugins to run when building the package
pkgPlugins :: [String]
} deriving (Eq, Generic, Ord, Show)
-- | Construct a library package.
library :: PackageName -> FilePath -> Package
library p fp = Package Library p (Internal fp) []
external :: PackageName -> String -> Package
external p v = Package Library p (External v) []
-- | Construct a program package.
program :: PackageName -> FilePath -> Package
program p fp = Package Program p (Internal fp) []
-- TODO: Remove this hack.
-- | A dummy package that we never try to build but use when we need a 'Package'
-- to construct a 'Context' but do not need to access the package field.
dummyPackage :: Package
dummyPackage = library "dummy" "dummy/path/"
-- | Is this a library package?
isLibrary :: Package -> Bool
isLibrary (Package (Library {}) _ _ _) = True
isLibrary _ = False
-- | Is this a program package?
isProgram :: Package -> Bool
isProgram (Package Program _ _ _) = True
isProgram _ = False
instance Binary PackageType
instance Hashable PackageType
instance NFData PackageType
instance Binary PackageLocation
instance Hashable PackageLocation
instance NFData PackageLocation
instance Binary Package
instance Hashable Package
instance NFData Package
{- Plugins -}
data Plugin = Plugin { pluginPackage :: Package
, pluginName :: String
, pluginOpts :: PluginArgs -> [String]
, initPhase :: PluginArgs -> Action ()
, finalPhase :: PluginArgs -> Action ()
}
data PluginArgs = PluginArgs { pluginOutput :: FilePath
, pluginTargetPackage :: Package }
addPlugin :: Plugin -> Package -> Package
addPlugin pl p = p { pkgPlugins = pkgName (pluginPackage pl) : pkgPlugins p }
|