packages feed

cabal-fix-0.0.0.1: app/cabal-fix.hs

{-# LANGUAGE OverloadedStrings #-}

-- | cabal-fix app
module Main where

import CabalFix
  ( Config,
    defaultConfig,
    fixCabalFields,
    fixCabalFile,
    parseCabalFields,
    printCabalFields,
  )
import CabalFix.Patch
import Control.Monad
import Data.Bool
import Data.ByteString qualified as BS
import Data.ByteString.Char8 qualified as C
import Data.Text.Lazy.IO qualified as Text
import Data.TreeDiff
import GHC.Generics
import Options.Applicative
import System.Directory
import System.FilePath
import Text.Pretty.Simple
import Prelude

data CommandType = FixInplace | FixCheck | GenerateConfig deriving (Generic, Eq, Show)

data Options = Options
  { commandType :: CommandType,
    projectDir :: FilePath,
    configFile :: FilePath
  }
  deriving (Eq, Show)

defaultOptions :: Options
defaultOptions = Options FixCheck "." "cabal-fix.config"

parseCommand :: Parser CommandType
parseCommand =
  subparser $
    command "inplace" (info (pure FixInplace) (progDesc "fix cabal file inplace"))
      <> command "check" (info (pure FixCheck) (progDesc "check cabal file"))
      <> command "genConfig" (info (pure GenerateConfig) (progDesc "generate config file"))

parseOptions :: Parser Options
parseOptions =
  Options
    <$> parseCommand
    <*> option str (Options.Applicative.value (projectDir defaultOptions) <> long "directory" <> short 'd' <> help "project directory")
    <*> option str (Options.Applicative.value (configFile defaultOptions) <> long "config" <> short 'c' <> help "config file")

infoOptions :: ParserInfo Options
infoOptions =
  info
    (parseOptions <**> helper)
    (fullDesc <> progDesc "cabal fixer" <> header "fixes your cabal file")

main :: IO ()
main = do
  o <- execParser infoOptions
  runCabalFix o

runCabalFix :: Options -> IO ()
runCabalFix o = do
  case commandType o of
    GenerateConfig ->
      Text.writeFile (configFile o) (pShowNoColor defaultConfig)
    FixInplace -> do
      cfg <- getConfig o
      fp <- getCabalFile o
      b <- fixCabalFile fp cfg
      unless b (putStrLn "parsing failure")
    FixCheck -> do
      cfg <- getConfig o
      fp <- getCabalFile o
      bs <- BS.readFile fp
      let bs' = printCabalFields cfg . fixCabalFields cfg <$> parseCabalFields cfg bs
      print $ fmap ansiWlBgEditExpr . patch (C.lines bs) . C.lines <$> bs'

getConfig :: Options -> IO Config
getConfig o = do
  configExists <- doesFileExist (configFile o)
  bool (pure defaultConfig) (read <$> readFile (configFile o)) configExists

getCabalFile :: Options -> IO FilePath
getCabalFile o = do
  fs <- getDirectoryContents (projectDir o)
  case filter ((== ".cabal") . takeExtension) fs of
    [] -> error "No .cabal file found"
    [c] -> pure (projectDir o </> c)
    _ -> error "multiple .cabal files found"