diff --git a/main/Main.hs b/main/Main.hs index f67fd501..99c592c8 100644 --- a/main/Main.hs +++ b/main/Main.hs @@ -5,7 +5,9 @@ module Main where -import Control.Concurrent (Chan, forkIO, newChan, readChan, writeChan) +import Control.Monad (unless) +import Control.Monad.Trans.Class (lift) +import Control.Monad.Trans.State.Strict (StateT, evalStateT, get, put) import Data.ByteString.Char8 (unpack) import Data.Either (lefts) import Data.FileEmbed @@ -87,19 +89,31 @@ data Target = Target } -- | Recursively collect nix files in a directory -collectNixFiles :: FilePath -> IO [FilePath] +collectNixFiles :: FilePath -> StateT Bool IO [FilePath] collectNixFiles path = do - dir <- doesDirectoryExist path + dir <- lift $ doesDirectoryExist path if | dir -> do - files <- listDirectory path + warnDeprecated + files <- lift $ listDirectory path concat <$> mapM collectNixFiles ((path ) <$> files) | ".nix" `isSuffixOf` path -> pure [path] - | otherwise -> pure [] + | otherwise -> do + warnDeprecated + pure [] + where + warnDeprecated = do + warningPrinted <- get + -- We don't want to print the warning more than once + unless warningPrinted $ do + lift $ hPutStrLn stderr $ "\ESC[33mPassing directories or non-Nix files (such as \"" <> path <> "\") is deprecated and will be unsupported soon, please use https://treefmt.com/ instead, e.g. via https://github.com/numtide/treefmt-nix\ESC[0m" + put True -- | Recursively collect nix files in a list of directories collectAllNixFiles :: [FilePath] -> IO [FilePath] -collectAllNixFiles paths = concat <$> mapM collectNixFiles paths +collectAllNixFiles paths = + -- The state represents whether a deprecation warning was already printed for a directory being passed + flip evalStateT False $ concat <$> mapM collectNixFiles paths formatTarget :: Formatter -> Target -> IO Result formatTarget format Target{tDoRead, tPath, tDoWrite} = do @@ -159,37 +173,16 @@ toWriteError Nixfmt{quiet = True} = const $ return () toJobs :: Nixfmt -> IO [IO Result] toJobs opts = map (toOperation opts $ toFormatter opts) <$> toTargets opts --- TODO: Efficient parallel implementation. This is just a sequential stub. --- This was originally implemented using parallel-io, but it gave a factor two --- overhead. -doParallel :: [IO a] -> IO [a] -doParallel = sequence - -errorWriter :: (String -> IO ()) -> Chan (Maybe String) -> Chan () -> IO () -errorWriter doWrite chan done = do - item <- readChan chan - case item of - Nothing -> return () - Just msg -> doWrite msg >> errorWriter doWrite chan done - writeChan done () - -writeErrorBundle :: Chan (Maybe String) -> Result -> IO Result -writeErrorBundle chan result = do +writeErrorBundle :: (String -> IO ()) -> Result -> IO Result +writeErrorBundle doWrite result = do case result of Right () -> return () - Left err -> writeChan chan $ Just err + Left err -> doWrite err return result -- | Run a list of jobs and write errors to stderr without interleaving them. runJobs :: (String -> IO ()) -> [IO Result] -> IO [Result] -runJobs writeError jobs = do - errChan <- newChan - doneChan <- newChan - _ <- forkIO $ errorWriter writeError errChan doneChan - results <- doParallel $ map (>>= writeErrorBundle errChan) jobs - writeChan errChan Nothing - _ <- readChan doneChan - return results +runJobs writeError = mapM (>>= writeErrorBundle writeError) main :: IO () main = withUtf8StdHandles $ do diff --git a/nixfmt.cabal b/nixfmt.cabal index 57073e6f..97e312a4 100644 --- a/nixfmt.cabal +++ b/nixfmt.cabal @@ -37,6 +37,7 @@ executable nixfmt , nixfmt , unix >= 2.7.2 && < 2.9 , text >= 1.2.3 && < 2.2 + , transformers -- for System.IO.Atomic , directory >= 1.3.3 && < 1.4