# Turns # # { # "hello.aarch64-linux": "a", # "hello.x86_64-linux": "b", # "hello.aarch64-darwin": "c", # "hello.x86_64-darwin": "d" # } # # into # # { # "hello": { # "linux": { # "aarch64": "a", # "x86_64": "b" # }, # "darwin": { # "aarch64": "c", # "x86_64": "d" # } # } # } # # while filtering out any attribute paths that don't match this pattern def expand_system: to_entries | map( .key |= split(".") | select(.key | length > 1) | .double = (.key[-1] | split("-")) | select(.double | length == 2) ) | group_by(.key[0:-1]) | map( { key: .[0].key[0:-1] | join("."), value: group_by(.double[1]) | map( { key: .[0].double[1], value: map(.key = .double[0]) | from_entries } ) | from_entries }) | from_entries ; # Transposes # # { # "a": [ "x", "y" ], # "b": [ "x" ], # } # # into # # { # "x": [ "a", "b" ], # "y": [ "a" ] # } def transpose: [ to_entries[] | { key: .key, value: .value[] } ] | group_by(.value) | map({ key: .[0].value, value: map(.key) }) | from_entries ; # Computes the key difference for two objects: # { # added: [ ], # removed: [ ], # changed: [ ], # } # def diff($before; $after): { added: $after | delpaths($before | keys | map([.])) | keys, removed: $before | delpaths($after | keys | map([.])) | keys, changed: $before | to_entries | map( $after."\(.key)" as $after2 | select( # Filter out attributes that don't exist anymore ($after2 != null) and # Filter out attributes that are the same as the new value (.value != $after2) ) | .key ) } ; ($before[0] | expand_system) as $before | ($after[0] | expand_system) as $after | .attrdiff = diff($before; $after) | .rebuildsByKernel = ( [ ( .attrdiff.changed[] | { key: ., value: diff($before."\(.)"; $after."\(.)").changed } ) , ( .attrdiff.added[] | { key: ., value: ($after."\(.)" | keys) } ) ] | from_entries | transpose ) | .rebuildCountByKernel = ( .rebuildsByKernel | with_entries(.value |= length) | pick(.linux, .darwin) | { linux: (.linux // 0), darwin: (.darwin // 0), } ) | .labels = ( .rebuildCountByKernel | to_entries | map( "10.rebuild-\(.key): " + if .value == 0 then "0" elif .value <= 10 then "1-10" elif .value <= 100 then "11-100" elif .value <= 500 then "101-500" elif .value <= 1000 then "501-1000" elif .value <= 2500 then "1001-2500" elif .value <= 5000 then "2501-5000" else "5001+" end ) )