packages feed

ghcflags 1.0.0 → 1.0.1

raw patch · 2 files changed

+46/−22 lines, 2 filesdep +timePVP ok

version bump matches the API change (PVP)

Dependencies added: time

API changes (from Hackage documentation)

Files

GhcFlags/Plugin.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE TupleSections #-}  -- | A ghc plugin that creates `.ghc.flags` files (and `.ghc.version`) populated --   with the flags that were last used to invoke ghc for some modules, for@@ -11,15 +12,19 @@ where  import qualified Config as GHC-import           Control.Monad (when)-import           Control.Monad.IO.Class (liftIO)-import           Data.Foldable (traverse_)-import           Data.List (stripPrefix)+import Control.Exception (finally, onException)+import Control.Monad (unless, when)+import Control.Monad.IO.Class (MonadIO, liftIO)+import Data.Foldable (traverse_)+import Data.IORef+import Data.List (stripPrefix)+import Data.Time.Clock (diffTimeToPicoseconds, getCurrentTime, utctDayTime) import qualified GHC import qualified GhcPlugins as GHC-import           System.Directory (doesFileExist)-import           System.Environment-import           System.IO.Error (catchIOError)+import System.Directory (doesFileExist, removeFile, renameFile)+import System.Environment+import System.IO.Error (catchIOError)+import System.IO.Unsafe (unsafePerformIO)  plugin :: GHC.Plugin plugin =@@ -30,16 +35,31 @@ #endif     } +-- Only run "write" once per process, unfortunately there is no other way to+-- inject an IORef except to use Unsafe.+lock :: IORef Bool+lock = unsafePerformIO $ newIORef False+ install :: [GHC.CommandLineOption] -> [GHC.CoreToDo] -> GHC.CoreM [GHC.CoreToDo] install _ core = do+  written <- liftIO $ atomicModifyIORef' lock (True,)+  unless written write+  pure core++-- TODO this only supports ghc being called with directories and home modules.+-- That means we don't support incremental compilation where ghc is called with+-- explicit filenames and dependencies. There are cases where the .ghc.flags may+-- get out of date, e.g. adding / removing home modules. To handle those cases+-- we need to detect them and write to a different (per-file) .ghc.flags+-- location. Text editors need to be aware of both kinds of ghc flags files and+-- use the most recent.+write :: (MonadIO m, GHC.HasDynFlags m) => m ()+write = do   dflags <- GHC.getDynFlags   args <- liftIO $ getArgs    -- downstream tools shouldn't use this plugin, or all hell will break loose   let ghcFlags = unwords $ replace ["-fplugin", "GhcFlags.Plugin"] [] args--      -- TODO this currently only supports ghc being called with directories and-      -- home modules, we should also support calling with explicit file names.       paths = GHC.importPaths dflags       writeGhcFlags path = writeDifferent (path <> "/.ghc.flags") ghcFlags       enable = case GHC.hscTarget dflags of@@ -51,17 +71,24 @@     traverse_ writeGhcFlags paths     writeDifferent ".ghc.version" GHC.cProjectVersion -  pure core---- only writes out the file when it will result in changes, and silently fails--- on exceptions because the plugin should never interrupt normal ghc work.+-- Only writes out the file when it will result in changes, and silently fails+-- on exceptions because the plugin should never interrupt normal ghc work. The+-- write is done atomically (via a temp file) otherwise it is prone to a lot of+-- crosstalk and then all writers fail to update the file. writeDifferent :: FilePath -> String -> IO () writeDifferent file content =-  ignoreIOExceptions-    $ whenM isDifferent (writeFile file content)+  ignoreIOExceptions . whenM isDifferent $ do+    time <- getCurrentTime+    let hash = diffTimeToPicoseconds . utctDayTime $ time+        tmp = file <> "." <> show hash+    finally+      (writeFile tmp content >> renameFile tmp file)+      (removeFile tmp)   where     isDifferent =-      ifM (doesFileExist file) ((content /=) <$> readFile file) (pure True)+      onException+        (ifM (doesFileExist file) ((content /=) <$> readFile file) (pure True))+        (pure True)  -- from Data.List.Extra replace :: Eq a => [a] -> [a] -> [a] -> [a]
ghcflags.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name:          ghcflags-version:       1.0.0+version:       1.0.1 synopsis:      Dump the ghc flags during compilation license:       BSD-2-Clause license-file:  LICENSE@@ -24,10 +24,7 @@     , base       >=4.11 && <5     , directory     , ghc--  --    , containers-  --    , ghc-boot-  --    , time+    , time    ghc-options:      -Wall -Werror=missing-home-modules   default-language: Haskell2010