Skip to content

Commit

Permalink
Compact input derivation diffs (#86)
Browse files Browse the repository at this point in the history
Before:

    • The input derivation named `bash-5.2p32` differs
      • These two derivations have already been compared
    • The input derivation named `curl-8.9.1` differs
      • These two derivations have already been compared
    • The input derivation named `mirrors-list` differs
      • These two derivations have already been compared
    • The input derivation named `stdenv-linux` differs
      • These two derivations have already been compared

After:

    • Input derivations differ but have already been compared
        bash-5.2p32
        curl-8.9.1
        mirrors-list
        stdenv-linux

This change reduced the output from a large diff of two production NixOS
systems from 190,769 lines to 142,871 lines, for a 25% reduction in
output.
  • Loading branch information
9999years authored Oct 25, 2024
1 parent a27abbd commit 83aa9a9
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 0 deletions.
1 change: 1 addition & 0 deletions app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ transformDiff :: TransformOptions -> DerivationDiff -> DerivationDiff
transformDiff TransformOptions{..}
= transformIf foldAlreadyCompared foldAlreadyComparedSubTrees
. transformIf squashTextDiff squashSourcesAndEnvsDiff
. foldManyInputDerivationsAlreadyCompared

renderDiff :: RenderRunner -> RenderContext -> DerivationDiff -> IO ()
renderDiff HumanReadable context derivation
Expand Down
4 changes: 4 additions & 0 deletions src/Nix/Diff/Render/HumanReadable.hs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ renderDiffHumanReadable = \case
renderWith extraPartsDiff \(sign, extraPaths) -> do
forM_ (Data.Map.toList extraPaths) \(extraPath, outputs) -> do
echo (" " <> sign (Store.toText extraPath <> renderOutputs outputs))
renderInputDerivationsDiff ManyDerivationsAlreadyComparedDiff{..} = do
echo (explain "Input derivations differ but have already been compared")
forM_ (Data.Set.toList drvNames) \name -> do
echo (" " <> name)

renderEnvDiff Nothing =
echo (explain "Skipping environment comparison")
Expand Down
58 changes: 58 additions & 0 deletions src/Nix/Diff/Transformations.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import qualified Patience
import Data.Generics.Uniplate.Data ( transformBi )

import Nix.Diff.Types
import qualified Data.Set as Set
import Data.Text (Text)

{-| In large diffs there may be a lot of derivations
that doesn't change at all, but changed some of
Expand Down Expand Up @@ -55,6 +57,61 @@ foldAlreadyComparedSubTrees dd = case dd of
foldAlreadyComparedSubTrees
inputsDiff

{-| If packages deep in the dependency graph have been changed, many other
derivations will also change in an uninteresting manner. This can lead to
hundreds or thousands of lines of output like this:
```
• The input derivation named `bash-5.2p32` differs
• These two derivations have already been compared
• The input derivation named `ensure-newer-sources-hook` differs
• These two derivations have already been compared
• The input derivation named `pypa-install-hook` differs
• These two derivations have already been compared
```
This transformation will fold sequences of `OneDerivationDiff` like this
into a single `ManyDerivationsAlreadyComparedDiff`.
-}
foldManyInputDerivationsAlreadyCompared :: DerivationDiff -> DerivationDiff
foldManyInputDerivationsAlreadyCompared dd = case dd of
DerivationsAreTheSame -> dd
AlreadyCompared -> dd
OnlyAlreadyComparedBelow{} -> dd
NamesDontMatch{} -> dd
OutputsDontMatch{} -> dd
DerivationDiff{..} ->
let inputsDiff' = transformNestedDerivationDiffs
foldManyInputDerivationsAlreadyCompared
inputsDiff

helper :: [Text] -> [InputDerivationsDiff] -> [InputDerivationsDiff]
helper [] [] = []
helper names [] =
[ManyDerivationsAlreadyComparedDiff
{ drvNames = Set.fromList names
}]
helper names (input:inputs) =
case input of
OneDerivationDiff
{ drvName
, drvDiff = AlreadyCompared
} -> helper
(drvName:names)
inputs
OneDerivationDiff{} -> input : helper names inputs
SomeDerivationsDiff{} -> input : helper names inputs
ManyDerivationsAlreadyComparedDiff{} -> error "unreachable"

in DerivationDiff
{ inputsDiff =
inputsDiff'
{ inputDerivationDiffs =
helper [] (inputDerivationDiffs inputsDiff')
}
, ..
}

{-| This transformation is most useful for
--json output, because it will sqash a lot of
`{"content":" ","type":"Both"},{"content":"When","type":"Both"},{"content":" ","type":"Both"},{"content":"in","type":"Both"},{"content":" ","type":"Both"}`
Expand Down Expand Up @@ -96,6 +153,7 @@ transformNestedDerivationDiffs f InputsDiff{..} = InputsDiff
OneDerivationDiff name dd ->
OneDerivationDiff name (f dd)
SomeDerivationsDiff {} -> idd
ManyDerivationsAlreadyComparedDiff {} -> idd

envSkippedOrUnchanged :: Maybe EnvironmentDiff -> Bool
envSkippedOrUnchanged = \case
Expand Down
4 changes: 4 additions & 0 deletions src/Nix/Diff/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,10 @@ data InputDerivationsDiff
{ drvName :: Text
, extraPartsDiff :: Changed (Map StorePath OutputNames)
}
| -- | Many input derivations differ, but they've all already been compared.
ManyDerivationsAlreadyComparedDiff
{ drvNames :: Set Text
}
deriving stock (Eq, Show, Generic, Data)
deriving anyclass (ToJSON, FromJSON)
deriving Arbitrary via GenericArbitrary InputDerivationsDiff
Expand Down

0 comments on commit 83aa9a9

Please sign in to comment.