packages feed

nix-diff 1.0.7 → 1.0.8

raw patch · 2 files changed

+97/−53 lines, 2 files

Files

nix-diff.cabal view
@@ -1,5 +1,5 @@ name:                nix-diff-version:             1.0.7+version:             1.0.8 synopsis:            Explain why two Nix derivations differ description:         This package provides a @nix-diff@ executable which                      explains why two Nix derivations (i.e. @*.drv@ files)
src/Main.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE ApplicativeDo              #-}+{-# LANGUAGE DuplicateRecordFields      #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE NamedFieldPuns             #-} {-# LANGUAGE OverloadedStrings          #-}@@ -24,7 +25,7 @@  import qualified Control.Monad.Reader import qualified Control.Monad.State-import qualified Data.Algorithm.Diff+import qualified Data.Algorithm.Diff       as Diff import qualified Data.Attoparsec.Text import qualified Data.Map import qualified Data.Set@@ -57,15 +58,37 @@             "never"  -> return Never             _        -> fail "Invalid color" -data Options = Options { left :: FilePath, right :: FilePath, color :: Color }+parseLineOriented :: Parser Bool+parseLineOriented =+    Options.Applicative.switch+        (   Options.Applicative.long "line-oriented"+        <>  Options.Applicative.help "Display textual differences on a per-line basis instead of a per-character basis"+        ) +parseEnvironment :: Parser Bool+parseEnvironment =+    Options.Applicative.switch+        (   Options.Applicative.long "environment"+        <>  Options.Applicative.help "Force display of environment differences"+        )++data Options = Options+    { left         :: FilePath+    , right        :: FilePath+    , color        :: Color+    , lineOriented :: Bool+    , environment  :: Bool+    }+ parseOptions :: Parser Options parseOptions = do-    left  <- parseLeft-    right <- parseRight-    color <- parseColor+    left         <- parseLeft+    right        <- parseRight+    color        <- parseColor+    lineOriented <- parseLineOriented+    environment  <- parseEnvironment -    return (Options { left, right, color })+    return (Options { left, right, color, lineOriented, environment })   where     parseFilePath metavar = do         Options.Applicative.strArgument@@ -84,8 +107,10 @@         )  data Context = Context-    { tty    :: TTY-    , indent :: Natural+    { tty          :: TTY+    , indent       :: Natural+    , lineOriented :: Bool+    , environment  :: Bool     }  newtype Status = Status { visited :: Set Diffed }@@ -180,9 +205,11 @@ red NotTTY text = text  -- | Color text background red-redBackground  :: TTY -> Text -> Text-redBackground  IsTTY text = "\ESC[41m" <> text <> "\ESC[0m"-redBackground NotTTY text = "←" <> text <> "←"+redBackground  :: Bool -> TTY -> Text -> Text+redBackground False IsTTY  text = "\ESC[41m" <> text <> "\ESC[0m"+redBackground True  IsTTY  text = "\ESC[41m" <> text <> "\ESC[0m\n"+redBackground False NotTTY text = "←" <> text <> "←"+redBackground True  NotTTY text = "- " <> text <> "\n"  -- | Color text green green :: TTY -> Text -> Text@@ -190,14 +217,18 @@ green NotTTY text = text  -- | Color text background green-greenBackground :: TTY -> Text -> Text-greenBackground  IsTTY text = "\ESC[42m" <> text <> "\ESC[0m"-greenBackground NotTTY text = "→" <> text <> "→"+greenBackground :: Bool -> TTY -> Text -> Text+greenBackground False IsTTY  text = "\ESC[42m" <> text <> "\ESC[0m"+greenBackground True  IsTTY  text = "\ESC[42m" <> text <> "\ESC[0m\n"+greenBackground False NotTTY text = "→" <> text <> "→"+greenBackground True  NotTTY text = "+ " <> text <> "\n"  -- | Color text grey-grey :: TTY -> Text -> Text-grey  IsTTY text = "\ESC[1;2m" <> text <> "\ESC[0m"-grey NotTTY text = text+grey :: Bool -> TTY -> Text -> Text+grey False  IsTTY text = "\ESC[1;2m" <> text <> "\ESC[0m"+grey True   IsTTY text = "\ESC[1;2m" <> text <> "\ESC[0m\n"+grey False NotTTY text = text+grey True  NotTTY text = "  " <> text <> "\n"  -- | Format the left half of a diff minus :: TTY -> Text -> Text@@ -273,6 +304,11 @@         then return ()         else diffOutput key leftOutput rightOutput +mapDiff :: (a -> b) -> Diff.Diff a -> Diff.Diff b+mapDiff f (Diff.First  l) = Diff.First (f l)+mapDiff f (Diff.Second r) = Diff.Second (f r)+mapDiff f (Diff.Both l r) = Diff.Both (f l) (f r)+ -- | Diff two `Text` values diffText     :: Text@@ -281,14 +317,22 @@     -- ^ Right value to compare     -> Diff Text diffText left right = do-    Context { indent, tty } <- ask+    Context { indent, lineOriented, tty } <- ask     let n = fromIntegral indent      let leftString  = Data.Text.unpack left-        rightString = Data.Text.unpack right+    let rightString = Data.Text.unpack right -    let chunks = Data.Algorithm.Diff.getGroupedDiff leftString rightString+    let leftLines  = Data.Text.lines left+    let rightLines = Data.Text.lines right +    let chunks =+            if lineOriented+                then+                    Diff.getDiff leftLines rightLines+                else+                    fmap (mapDiff Data.Text.pack) (Diff.getGroupedDiff leftString rightString)+     let prefix = Data.Text.replicate n " "      let format text =@@ -301,12 +345,12 @@               where                 indentLine line = prefix <> "    " <> line -    let renderChunk (Data.Algorithm.Diff.First  l) =-            redBackground   tty (Data.Text.pack l)-        renderChunk (Data.Algorithm.Diff.Second r) =-            greenBackground tty (Data.Text.pack r)-        renderChunk (Data.Algorithm.Diff.Both l _) =-            grey            tty (Data.Text.pack l)+    let renderChunk (Diff.First  l) =+            redBackground   lineOriented tty l+        renderChunk (Diff.Second r) =+            greenBackground lineOriented tty r+        renderChunk (Diff.Both l _) =+            grey            lineOriented tty l      return (format (Data.Text.concat (fmap renderChunk chunks))) @@ -352,25 +396,24 @@                 text <- indented 4 (diffText leftValue rightValue)                 echo ("    " <> key <> "=" <> text) --- | Diff two environments+-- | Diff input sources diffSrcs     :: Set FilePath-    -- ^ Left derivation outputs+    -- ^ Left input sources     -> Set FilePath-    -- ^ Right derivation outputs-    -> Diff Bool+    -- ^ Right inputSources+    -> Diff () diffSrcs leftSrcs rightSrcs = do     let leftExtraSrcs  = Data.Set.difference leftSrcs  rightSrcs     let rightExtraSrcs = Data.Set.difference rightSrcs leftSrcs      if Data.Set.null leftExtraSrcs && Data.Set.null rightExtraSrcs-        then return True+        then return ()         else do             echo (explain "The set of input sources do not match:")             diffWith leftExtraSrcs rightExtraSrcs $ \(sign, extraSrcs) -> do                 forM_ extraSrcs $ \extraSrc -> do                     echo ("    " <> sign (pathToText extraSrc))-            return False  diffPlatform :: Text -> Text -> Diff () diffPlatform leftPlatform rightPlatform = do@@ -399,12 +442,12 @@         echo (explain "The arguments do not match")         let leftList  = Data.Vector.toList leftArgs         let rightList = Data.Vector.toList rightArgs-        let diffs = Data.Algorithm.Diff.getDiff leftList rightList-        let renderDiff (Data.Algorithm.Diff.First arg) =+        let diffs = Diff.getDiff leftList rightList+        let renderDiff (Diff.First arg) =                 echo ("    " <> minus tty arg)-            renderDiff (Data.Algorithm.Diff.Second arg) =+            renderDiff (Diff.Second arg) =                 echo ("    " <> plus tty arg)-            renderDiff (Data.Algorithm.Diff.Both arg _) =+            renderDiff (Diff.Both arg _) =                 echo ("    " <> explain arg)         mapM_ renderDiff diffs @@ -448,6 +491,10 @@             let rightArgs = Nix.Derivation.args rightDerivation             diffArgs leftArgs rightArgs +            let leftSrcs  = Nix.Derivation.inputSrcs leftDerivation+            let rightSrcs = Nix.Derivation.inputSrcs rightDerivation+            diffSrcs leftSrcs rightSrcs+             let leftInputs  = groupByName (Nix.Derivation.inputDrvs leftDerivation)             let rightInputs = groupByName (Nix.Derivation.inputDrvs rightDerivation) @@ -482,27 +529,24 @@                             forM_ (Data.Map.toList extraPaths) $ \(extraPath, outputs) -> do                                 echo ("    " <> sign (pathToText extraPath <> renderOutputs outputs))                         return False-            if or descended-            then return ()-            else do-                let leftSrcs  = Nix.Derivation.inputSrcs leftDerivation-                let rightSrcs = Nix.Derivation.inputSrcs rightDerivation-                differed <- diffSrcs leftSrcs rightSrcs -                if not differed-                then return ()-                else do-                    let leftEnv  = Nix.Derivation.env leftDerivation-                    let rightEnv = Nix.Derivation.env rightDerivation-                    let leftOutNames  = Data.Map.keysSet leftOuts-                    let rightOutNames = Data.Map.keysSet rightOuts-                    diffEnv leftOutNames rightOutNames leftEnv rightEnv+            Context { environment } <- ask +            if or descended && not environment+            then do+                echo (explain "Skipping environment comparison")+            else do+                let leftEnv  = Nix.Derivation.env leftDerivation+                let rightEnv = Nix.Derivation.env rightDerivation+                let leftOutNames  = Data.Map.keysSet leftOuts+                let rightOutNames = Data.Map.keysSet rightOuts+                diffEnv leftOutNames rightOutNames leftEnv rightEnv+ main :: IO () main = do     GHC.IO.Encoding.setLocaleEncoding GHC.IO.Encoding.utf8 -    Options { left, right, color } <- Options.Applicative.execParser parserInfo+    Options { left, right, color, lineOriented, environment } <- Options.Applicative.execParser parserInfo      tty <- case color of         Never -> do@@ -514,7 +558,7 @@             return (if b then IsTTY else NotTTY)      let indent = 0-    let context = Context { tty, indent }+    let context = Context { tty, indent, lineOriented, environment }     let status = Status Data.Set.empty     let action = diff True left (Data.Set.singleton "out") right (Data.Set.singleton "out")     Control.Monad.State.evalStateT (Control.Monad.Reader.runReaderT (unDiff action) context) status