packages feed

cabal-buck2-0.2.0.0: src/Distribution/Client/Buck2/Setup.hs

-- | Set up the project for building with @buck2@
module Distribution.Client.Buck2.Setup
  ( checkBuck2Prelude
  , ensureBuckconfigAndPackage
  ) where

import Distribution.Client.Compat.Prelude
import Prelude ()

import Data.List (stripPrefix)
import System.Directory (doesDirectoryExist, doesFileExist)
import System.FilePath ((</>))

import Distribution.Simple.Utils (die', notice)

import Distribution.Client.Buck2.Version (cabalBuck2Version)


-- | Check that the @buck2@ support code is at @buck2\/@, and that it is for
-- this release of @cabal-buck2@: the files it generates are only understood by
-- the same release of it, which is a branch of that name.
checkBuck2Prelude :: Verbosity -> FilePath -> IO ()
checkBuck2Prelude verbosity projectRoot = do
  exists <- doesDirectoryExist buck2Dir
  unless exists $
    die' verbosity $
      unlines
        [ "No 'buck2/' directory found in the project root."
        , "Clone the buck2 prelude and support scripts with:"
        , ""
        , "    git clone --branch " ++ cabalBuck2Version ++ " https://github.com/simonmar/haskell-buck2 buck2"
        , ""
        , "then re-run 'cabal buck2'."
        ]
  found <- readBuck2Version buck2Dir
  case found of
    Just v | v == cabalBuck2Version -> return ()
    _ ->
      die' verbosity $
        unlines
          [ "The 'buck2/' directory is not for this release of cabal-buck2."
          , ""
          , "This is cabal-buck2 " ++ cabalBuck2Version ++ ", and buck2/ is for " ++ maybe "no release (it is from an earlier one)" ("cabal-buck2 " ++) found ++ "."
          , ""
          , "cabal-buck2 " ++ cabalBuck2Version ++ " needs the " ++ cabalBuck2Version ++ " branch of https://github.com/simonmar/haskell-buck2. If buck2/ is a git checkout, switch it with:"
          , ""
          , "    git -C buck2 fetch && git -C buck2 checkout " ++ cabalBuck2Version
          , ""
          , "or use the cabal-buck2 release that matches the buck2/ you have."
          ]
  where
    buck2Dir = projectRoot </> "buck2"

-- | The release of @cabal-buck2@ that a checkout of @haskell-buck2@ is for,
-- from its @version.bzl@ (@CABAL_BUCK2_VERSION = "..."@).
readBuck2Version :: FilePath -> IO (Maybe String)
readBuck2Version buck2Dir = do
  let path = buck2Dir </> "version.bzl"
  exists <- doesFileExist path
  if not exists
    then return Nothing
    else do
      contents <- readFile path
      return $ listToMaybe [takeWhile (/= '"') rest | l <- lines contents, Just rest <- [stripPrefix "CABAL_BUCK2_VERSION = \"" l]]

-- | Copy @.buckconfig@ and @PACKAGE@ if they don't exist
ensureBuckconfigAndPackage :: Verbosity -> FilePath -> IO ()
ensureBuckconfigAndPackage verbosity projectRoot = do
  copyIfMissing verbosity (exampleDir </> ".buckconfig") (projectRoot </> ".buckconfig")
  copyIfMissing verbosity (exampleDir </> "PACKAGE") (projectRoot </> "PACKAGE")
  where
    exampleDir = projectRoot </> "buck2" </> "example"

copyIfMissing :: Verbosity -> FilePath -> FilePath -> IO ()
copyIfMissing verbosity src dest = do
  exists <- doesFileExist dest
  unless exists $ do
    contents <- readFile src
    writeFile dest contents
    notice verbosity $ "cabal buck2: created " ++ dest ++ " (from " ++ src ++ ")"