Skip to content

Commit b4a4f16

Browse files
committed
Translate block device arrayrefs to hashrefs
Restructure the output of `lsblk --json` to convert arrayrefs of block device hashrefs to hashrefs of block device hashrefs, indexed by the block device name, to avoid an error with array processing raised by ELK: > <haxmeister> the error I see is "elastic search has limited support for arrays" Because devices usually have at least one level of sub-devices (logical partitions), and can have even more (e.g. encrypted devices), this needs to be done recursively, here implemented with an iterative breadth-first search over the whole tree. This restructuring does require that each device hashref has a "name" member with a unique value to form the index of the transformed hashref. It should print a warning if this is not the case or the data is in any other way formed in an unexpected way. None of this may be needed if we end up writing our own parser over `/sys/devices/.../block` per GitHub issue #47, but it was fun to write anyway. This should hopefully resolve GitHub issue #46.
1 parent 857db52 commit b4a4f16

File tree

1 file changed

+80
-2
lines changed

1 file changed

+80
-2
lines changed

lib/Funtoo/Report.pm

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,8 +409,86 @@ sub get_filesystem_info{
409409
my $json_from_lsblk =
410410
`lsblk --json -o NAME,FSTYPE,SIZE,MOUNTPOINT,PARTTYPE,RM,HOTPLUG,TRAN`;
411411
my $data = decode_json($json_from_lsblk);
412-
my %hash = %$data;
413-
return \%hash;
412+
413+
# we need to recursively transform the arrayref-of-hashref structures in
414+
# this output into hashrefs-of-hashrefs, indexed by the 'name' of each item
415+
416+
# start a stack of references to objects to transform
417+
my @stack;
418+
419+
# dispatch table of reference type to transformation method
420+
my %disp = (
421+
422+
# pass hashes through unscathed, enqueuing all their values
423+
HASH => sub {
424+
my $obj = shift;
425+
for my $value (values %{ $obj }) {
426+
push @stack, \$value;
427+
}
428+
return $obj;
429+
},
430+
431+
# convert an arrayref of hashrefs in-place into a hashref by the "name"
432+
# member of each hashref, and enqueue all the original items
433+
ARRAY => sub {
434+
my $obj = shift;
435+
436+
# start replacement hash
437+
my %rep;
438+
439+
# iterate over the list items
440+
for my $item (@{ $obj }) {
441+
442+
# ensure we can actually translate this item, warn and skip it
443+
# if we can't
444+
eval {
445+
my $type = ref $item
446+
or die;
447+
$type eq 'HASH'
448+
or die;
449+
exists $item->{name}
450+
or die;
451+
not exists $rep{$item->{name}}
452+
or die;
453+
454+
# item passes muster, put it into the replacement hash
455+
$rep{$item->{name}} = $item;
456+
push @stack, \$item;
457+
458+
} or warn "Failed arrayref item conversion\n";
459+
}
460+
461+
# return a reference to the replacement hash, not the original
462+
# arrayref; we discard that
463+
return \%rep;
464+
},
465+
);
466+
467+
# start with the root node on the stack
468+
push @stack, \$data;
469+
470+
# iterative walk through the tree
471+
while (@stack) {
472+
473+
# pop a reference off the stack
474+
my $ref = pop @stack;
475+
476+
# get the object it points to
477+
my $obj = ${ $ref };
478+
479+
# skip any object that is not itself a reference
480+
my $type = ref $obj
481+
or next;
482+
483+
# skip any object for which we don't have a handler defined
484+
exists $disp{$type}
485+
or next;
486+
487+
# repoint the reference to the outcome of this type's dispatch method
488+
${ $ref } = $disp{$type}->($obj);
489+
}
490+
491+
return $data;
414492
}
415493
##
416494
## fetching active profiles

0 commit comments

Comments
 (0)