Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion pkg/baseboard/baseboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,14 @@ func (i *Info) String() string {
// New returns a pointer to an Info struct containing information about the
// host's baseboard
func New(opts ...*option.Option) (*Info, error) {
ctx := context.New(opts...)
return newWithContext(context.New(opts...))
}

func NewWithContext(ctx *context.Context) (*Info, error) {
return newWithContext(context.FromParent(ctx))
}

func newWithContext(ctx *context.Context) (*Info, error) {
info := &Info{ctx: ctx}
if err := ctx.Do(info.load); err != nil {
return nil, err
Expand Down
9 changes: 8 additions & 1 deletion pkg/bios/bios.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,14 @@ func (i *Info) String() string {
// New returns a pointer to a Info struct containing information
// about the host's BIOS
func New(opts ...*option.Option) (*Info, error) {
ctx := context.New(opts...)
return newWithContext(context.New(opts...))
}

func NewWithContext(ctx *context.Context) (*Info, error) {
return newWithContext(context.FromParent(ctx))
}

func newWithContext(ctx *context.Context) (*Info, error) {
info := &Info{ctx: ctx}
if err := ctx.Do(info.load); err != nil {
return nil, err
Expand Down
9 changes: 8 additions & 1 deletion pkg/block/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,14 @@ type Info struct {
// New returns a pointer to an Info struct that describes the block storage
// resources of the host system.
func New(opts ...*option.Option) (*Info, error) {
ctx := context.New(opts...)
return newWithContext(context.New(opts...))
}

func NewWithContext(ctx *context.Context) (*Info, error) {
return newWithContext(context.FromParent(ctx))
}

func newWithContext(ctx *context.Context) (*Info, error) {
info := &Info{ctx: ctx}
if err := ctx.Do(info.load); err != nil {
return nil, err
Expand Down
9 changes: 8 additions & 1 deletion pkg/chassis/chassis.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,14 @@ func (i *Info) String() string {
// New returns a pointer to a Info struct containing information
// about the host's chassis
func New(opts ...*option.Option) (*Info, error) {
ctx := context.New(opts...)
return newWithContext(context.New(opts...))
}

func NewWithContext(ctx *context.Context) (*Info, error) {
return newWithContext(context.FromParent(ctx))
}

func newWithContext(ctx *context.Context) (*Info, error) {
info := &Info{ctx: ctx}
if err := ctx.Do(info.load); err != nil {
return nil, err
Expand Down
39 changes: 38 additions & 1 deletion pkg/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
package context

import (
"fmt"

"github.com/jaypipes/ghw/pkg/option"
"github.com/jaypipes/ghw/pkg/snapshot"
)
Expand All @@ -20,6 +22,8 @@ type Context struct {
SnapshotRoot string
SnapshotExclusive bool
alert option.Alerter
err error
parent *Context
}

// New returns a Context struct pointer that has had various options set on it
Expand Down Expand Up @@ -47,10 +51,17 @@ func New(opts ...*option.Option) *Context {
ctx.EnableTools = *merged.EnableTools
}

// New is not allowed to return error - it would break the established API.
// so the only way out is to actually do the checks here and record the error,
// and return it later, at the earliest possible occasion, in Setup()
if ctx.SnapshotPath != "" && ctx.Chroot != option.DefaultChroot {
// The env/client code supplied a value, but we are will overwrite it when unpacking shapshots!
ctx.err = fmt.Errorf("Conflicting options: chroot %q and snapshot path %q", ctx.Chroot, ctx.SnapshotPath)
}
return ctx
}

// FromEnv returns an Option that has been populated from the environs or
// FromEnv returns a Context that has been populated from the environs or
// default options values
func FromEnv() *Context {
chrootVal := option.EnvOrDefaultChroot()
Expand All @@ -67,6 +78,21 @@ func FromEnv() *Context {
}
}

// FromParent returns a Context which is subordinate to another one.
// This means only the parent Context is in charge to the environment (e.g. setting up the snapshot).
// Subordinate contexts will defer any environment-changing action to their parent.
func FromParent(ctx *Context) *Context {
return &Context{
Chroot: ctx.Chroot,
EnableTools: ctx.EnableTools,
SnapshotPath: ctx.SnapshotPath,
SnapshotRoot: ctx.SnapshotRoot,
SnapshotExclusive: ctx.SnapshotExclusive,
alert: ctx.alert,
parent: ctx,
}
}

// Do wraps a Setup/Teardown pair around the given function
func (ctx *Context) Do(fn func() error) error {
err := ctx.Setup()
Expand All @@ -83,6 +109,13 @@ func (ctx *Context) Do(fn func() error) error {
// You should call `Setup` just once. It is safe to call `Setup` if you don't make
// use of optional extra features - `Setup` will do nothing.
func (ctx *Context) Setup() error {
if ctx.err != nil {
return ctx.err
}
if ctx.parent != nil {
// nothing to do - the parent is in charge
return nil
}
if ctx.SnapshotPath == "" {
// nothing to do!
return nil
Expand Down Expand Up @@ -111,6 +144,10 @@ func (ctx *Context) Setup() error {
// You should always call `Teardown` if you called `Setup` to free any resources
// acquired by `Setup`. Check `Do` for more automated management.
func (ctx *Context) Teardown() error {
if ctx.parent != nil {
// nothing to do - the parent is in charge
return nil
}
if ctx.SnapshotRoot != "" {
// if the client code provided the unpack directory,
// then it is also in charge of the cleanup.
Expand Down
9 changes: 8 additions & 1 deletion pkg/cpu/cpu.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,14 @@ type Info struct {
// New returns a pointer to an Info struct that contains information about the
// CPUs on the host system
func New(opts ...*option.Option) (*Info, error) {
ctx := context.New(opts...)
return newWithContext(context.New(opts...))
}

func NewWithContext(ctx *context.Context) (*Info, error) {
return newWithContext(context.FromParent(ctx))
}

func newWithContext(ctx *context.Context) (*Info, error) {
info := &Info{ctx: ctx}
if err := ctx.Do(info.load); err != nil {
return nil, err
Expand Down
9 changes: 8 additions & 1 deletion pkg/gpu/gpu.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,14 @@ type Info struct {
// New returns a pointer to an Info struct that contains information about the
// graphics cards on the host system
func New(opts ...*option.Option) (*Info, error) {
ctx := context.New(opts...)
return newWithContext(context.New(opts...))
}

func NewWithContext(ctx *context.Context) (*Info, error) {
return newWithContext(context.FromParent(ctx))
}

func newWithContext(ctx *context.Context) (*Info, error) {
info := &Info{ctx: ctx}
if err := ctx.Do(info.load); err != nil {
return nil, err
Expand Down
9 changes: 8 additions & 1 deletion pkg/memory/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,14 @@ type Info struct {
}

func New(opts ...*option.Option) (*Info, error) {
ctx := context.New(opts...)
return newWithContext(context.New(opts...))
}

func NewWithContext(ctx *context.Context) (*Info, error) {
return newWithContext(context.FromParent(ctx))
}

func newWithContext(ctx *context.Context) (*Info, error) {
info := &Info{ctx: ctx}
if err := ctx.Do(info.load); err != nil {
return nil, err
Expand Down
9 changes: 8 additions & 1 deletion pkg/net/net.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,14 @@ type Info struct {
// New returns a pointer to an Info struct that contains information about the
// network interface controllers (NICs) on the host system
func New(opts ...*option.Option) (*Info, error) {
ctx := context.New(opts...)
return newWithContext(context.New(opts...))
}

func NewWithContext(ctx *context.Context) (*Info, error) {
return newWithContext(context.FromParent(ctx))
}

func newWithContext(ctx *context.Context) (*Info, error) {
info := &Info{ctx: ctx}
if err := ctx.Do(info.load); err != nil {
return nil, err
Expand Down
7 changes: 5 additions & 2 deletions pkg/option/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import (
)

const (
defaultChroot = "/"
DefaultChroot = "/"
)

const (
envKeyChroot = "GHW_CHROOT"
envKeyDisableWarnings = "GHW_DISABLE_WARNINGS"
envKeyDisableTools = "GHW_DISABLE_TOOLS"
Expand Down Expand Up @@ -57,7 +60,7 @@ func EnvOrDefaultChroot() string {
if val, exists := os.LookupEnv(envKeyChroot); exists {
return val
}
return defaultChroot
return DefaultChroot
}

// EnvOrDefaultSnapshotPath returns the value of the GHW_SNAPSHOT_PATH environs variable
Expand Down
31 changes: 21 additions & 10 deletions pkg/pci/pci.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,21 +151,32 @@ func (i *Info) String() string {
// New returns a pointer to an Info struct that contains information about the
// PCI devices on the host system
func New(opts ...*option.Option) (*Info, error) {
ctx := context.New(opts...)
return newWithContext(context.New(opts...))
}

func NewWithContext(ctx *context.Context) (*Info, error) {
return newWithContext(context.FromParent(ctx))
}

func newWithContext(ctx *context.Context) (*Info, error) {
// by default we don't report NUMA information;
// we will only if are sure we are running on NUMA architecture
arch := topology.ARCHITECTURE_SMP
topo, err := topology.NewWithContext(ctx)
if err == nil {
arch = topo.Architecture
} else {
ctx.Warn("error detecting system topology: %v", err)
}
info := &Info{
arch: arch,
arch: topology.ARCHITECTURE_SMP,
ctx: ctx,
}
if err := ctx.Do(info.load); err != nil {
// we do this trick because we need to make sure ctx.Setup() gets
// a chance to run before any subordinate package is created reusing
// our context.
if err := ctx.Do(func() error {
topo, err := topology.NewWithContext(ctx)
if err == nil {
info.arch = topo.Architecture
} else {
ctx.Warn("error detecting system topology: %v", err)
}
return info.load()
}); err != nil {
return nil, err
}
return info, nil
Expand Down
9 changes: 8 additions & 1 deletion pkg/product/product.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,14 @@ func (i *Info) String() string {
// New returns a pointer to a Info struct containing information
// about the host's product
func New(opts ...*option.Option) (*Info, error) {
ctx := context.New(opts...)
return newWithContext(context.New(opts...))
}

func NewWithContext(ctx *context.Context) (*Info, error) {
return newWithContext(context.FromParent(ctx))
}

func newWithContext(ctx *context.Context) (*Info, error) {
info := &Info{ctx: ctx}
if err := ctx.Do(info.load); err != nil {
return nil, err
Expand Down
6 changes: 5 additions & 1 deletion pkg/topology/topology.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,17 @@ type Info struct {
// New returns a pointer to an Info struct that contains information about the
// NUMA topology on the host system
func New(opts ...*option.Option) (*Info, error) {
return NewWithContext(context.New(opts...))
return newWithContext(context.New(opts...))
}

// NewWithContext returns a pointer to an Info struct that contains information about
// the NUMA topology on the host system. Use this function when you want to consume
// the topology package from another package (e.g. pci, gpu)
func NewWithContext(ctx *context.Context) (*Info, error) {
return newWithContext(context.FromParent(ctx))
}

func newWithContext(ctx *context.Context) (*Info, error) {
info := &Info{ctx: ctx}
if err := ctx.Do(info.load); err != nil {
return nil, err
Expand Down