{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} import Control.Monad (filterM) import Control.Monad.Extra (ifM) import qualified Data.ByteString as BS import qualified Data.List.NonEmpty as NEL import Data.Text.Encoding (encodeUtf8) import Distribution.Types.PackageName (mkPackageName) import Hpack (Force (..), Options (..), defaultOptions, hpackResult, setTarget) import StackageToHackage.Hackage (printFreeze, printProject, stackToCabal) import StackageToHackage.Stackage (localDirs, readStack) import System.Directory (doesDirectoryExist, doesFileExist, getCurrentDirectory, listDirectory) import System.FilePath (takeBaseName, takeExtension, ()) main :: IO () main = do dir <- getCurrentDirectory stack <- readStack =<< BS.readFile (dir "stack.yaml") let subs = NEL.toList $ (dir ) <$> localDirs stack hpacks <- filterM (\d -> doesFileExist $ hpackInput d) $ subs _ <- traverse runHpack hpacks cabals <- concat <$> traverse (globExt ".cabal") subs -- we could use the hpack output to figure out which cabal files to use, but -- that misses projects that have explicit .cabal files, so just scan. let ignore = (mkPackageName . takeBaseName) <$> cabals (project, freeze) <- stackToCabal ignore dir stack BS.writeFile (dir "cabal.project") (encodeUtf8 $ printProject project) BS.writeFile (dir "cabal.project.freeze") (encodeUtf8 $ printFreeze freeze) where hpackInput sub = sub "package.yaml" opts = defaultOptions {optionsForce = Force} runHpack sub = hpackResult $ setTarget (hpackInput sub) opts globExt :: String -> FilePath -> IO [FilePath] globExt ext path = do files <- ifM (doesDirectoryExist path) (listDirectory path) (pure []) pure $ filter ((ext ==) . takeExtension) files -- TODO invoke cabal v2-freeze to minimise the freeze file