content: -----------------------------------------------------------------------------
  -- |
  -- 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,
  
      -- * Construction and properties
      library, program, dummyPackage, isLibrary, isProgram,
  
      -- * Package directory structure
      pkgCabalFile
      ) where
  
  import Development.Shake.Classes
  import Development.Shake.FilePath
  import GHC.Generics
  
  import Hadrian.Utilities
  
  -- TODO: Make PackageType more precise.
  -- See https://github.com/snowleopard/hadrian/issues/12.
  data PackageType = Library | Program 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.
      pkgPath :: FilePath
      } deriving (Eq, Generic, Ord, Show)
  
  -- | Construct a library package.
  library :: PackageName -> FilePath -> Package
  library = Package Library
  
  -- | Construct a program package.
  program :: PackageName -> FilePath -> Package
  program = Package Program
  
  -- 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
  
  -- | The path to the Cabal file of a Haskell package, e.g. @ghc/ghc-bin.cabal@.
  pkgCabalFile :: Package -> FilePath
  pkgCabalFile p = pkgPath p -/- pkgName p <.> "cabal"
  
  instance Binary   PackageType
  instance Hashable PackageType
  instance NFData   PackageType
  
  instance Binary   Package
  instance Hashable Package
  instance NFData   Package
  