github.com/linuxboot/fiano@v1.2.0/pkg/visitors/flatten.go (about)

     1  // Copyright 2018 the LinuxBoot Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package visitors
     6  
     7  import (
     8  	"encoding/json"
     9  	"fmt"
    10  	"io"
    11  	"os"
    12  
    13  	"github.com/linuxboot/fiano/pkg/uefi"
    14  )
    15  
    16  // Flatten places all nodes into a single slice and removes their children.
    17  // Each node contains the index of its parent (the root node's parent is
    18  // itself). This format is suitable for insertion into a database.
    19  type Flatten struct {
    20  	// Optionally write result as JSON.
    21  	W io.Writer
    22  
    23  	// Outputted flattened tree.
    24  	List []FlattenedFirmware
    25  
    26  	parent int
    27  }
    28  
    29  // FlattenedFirmware appears in the Flatten.List, contains the index of the
    30  // parrent and has no children.
    31  type FlattenedFirmware struct {
    32  	Parent int
    33  	Type   string
    34  	Value  uefi.Firmware
    35  }
    36  
    37  // Run wraps Visit and performs some setup and teardown tasks.
    38  func (v *Flatten) Run(f uefi.Firmware) error {
    39  	if err := f.Apply(v); err != nil {
    40  		return err
    41  	}
    42  
    43  	// Remove children otherwise the output contains many duplicates of each node.
    44  	for _, f := range v.List {
    45  		switch f := f.Value.(type) {
    46  		case *uefi.BIOSRegion:
    47  			f.Elements = nil
    48  		case *uefi.File:
    49  			f.Sections = nil
    50  		case *uefi.FirmwareVolume:
    51  			f.Files = nil
    52  		case *uefi.FlashImage:
    53  			// TODO: Cannot remove IFD
    54  			// f.IFD = nil
    55  			f.Regions = nil
    56  		case *uefi.Section:
    57  			f.Encapsulated = nil
    58  		}
    59  	}
    60  
    61  	// Optionally print as JSON
    62  	if v.W != nil {
    63  		b, err := json.MarshalIndent(v.List, "", "\t")
    64  		if err != nil {
    65  			return err
    66  		}
    67  		_, err = fmt.Fprintln(v.W, string(b))
    68  		return err
    69  	}
    70  	return nil
    71  }
    72  
    73  // Visit applies the Flatten visitor to any Firmware type.
    74  func (v *Flatten) Visit(f uefi.Firmware) error {
    75  	parent := v.parent
    76  	v.parent = len(v.List)
    77  	v.List = append(v.List, FlattenedFirmware{
    78  		Parent: parent,
    79  		Type:   fmt.Sprintf("%T", f),
    80  		Value:  f,
    81  	})
    82  	if err := f.ApplyChildren(v); err != nil {
    83  		return err
    84  	}
    85  	v.parent = parent
    86  	return nil
    87  }
    88  
    89  func init() {
    90  	RegisterCLI("flatten", "prints a JSON list of nodes", 0, func(args []string) (uefi.Visitor, error) {
    91  		return &Flatten{
    92  			W: os.Stdout,
    93  		}, nil
    94  	})
    95  }