Skip to content

Commit

Permalink
feat: more stringent golangci-lint rules
Browse files Browse the repository at this point in the history
Adapted from https://github.com/nix-community/go-nix.

Local testing shows no diff in my local report when compared with `main`.

Closes #151

Signed-off-by: Brian McGee <brian@bmcgee.ie>
  • Loading branch information
brianmcgee committed Nov 12, 2024
1 parent e966906 commit 5b4a7a8
Show file tree
Hide file tree
Showing 75 changed files with 711 additions and 780 deletions.
34 changes: 34 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
linters:
enable:
- errname
- exhaustive
- gci
- goconst
- godot
- gofumpt
- goheader
- goimports
- gosec
- importas
- ireturn
- lll
- makezero
- misspell
- nakedret
- nestif
- nilerr
- nilnil
- noctx
- nolintlint
- prealloc
- predeclared
- revive
- rowserrcheck
- stylecheck
- tenv
- testpackage
- unconvert
- unparam
- wastedassign
- whitespace
- wsl
17 changes: 12 additions & 5 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,20 @@ func init() {
flag.StringVar(&outputPath, "output", "", "path to write the report")
flag.StringVar(&outputPath, "o", "", "path to write the report")
flag.BoolVar(&scanner.Swap, "swap", false, "capture swap entries")
flag.BoolVar(&scanner.Ephemeral, "ephemeral", false, "capture all ephemeral properties e.g. swap, filesystems and so on")
flag.BoolVar(
&scanner.Ephemeral, "ephemeral", false,
"capture all ephemeral properties e.g. swap, filesystems and so on",
)
flag.StringVar(&logLevel, "log-level", "info", "log level")

defaultFeatures := []string{
"memory", "pci", "net", "serial", "cpu", "bios", "monitor", "scsi", "usb", "prom", "sbus", "sys", "sysfs",
"udev", "block", "wlan",
}

probeFeatures := hwinfo.ProbeFeatureStrings()
filteredFeatures := []string{}
for _, feature := range probeFeatures {
var filteredFeatures []string

for _, feature := range hwinfo.ProbeFeatureStrings() {
if feature != "default" && feature != "int" {
filteredFeatures = append(filteredFeatures, feature)
}
Expand All @@ -47,8 +50,10 @@ func init() {
hardwareFeatures = strings.Split(flagValue, ",")
return nil
})

possibleValues := strings.Join(filteredFeatures, ",")
defaultValues := strings.Join(defaultFeatures, ",")

const usage = `nixos-facter [flags]
Hardware report generator
Expand Down Expand Up @@ -84,6 +89,7 @@ func Execute() {
if err != nil {
log.Fatalf("invalid hardware feature: %v", err)
}

scanner.Features = append(scanner.Features, probe)
}

Expand Down Expand Up @@ -114,8 +120,9 @@ func Execute() {
if _, err = os.Stdout.Write(bytes); err != nil {
log.Fatalf("failed to write report to stdout: %v", err)
}

fmt.Println()
} else if err = os.WriteFile(outputPath, bytes, 0o644); err != nil {
} else if err = os.WriteFile(outputPath, bytes, 0o600); err != nil {
log.Fatalf("failed to write report to output path: %v", err)
}
}
5 changes: 5 additions & 0 deletions pkg/ephem/ephem.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func StableDevicePath(device string) (string, error) {
if !strings.HasPrefix("/", device) {
return device, nil
}

stat, err := os.Stat(device)
if err != nil {
return "", err
Expand All @@ -41,14 +42,18 @@ func StableDevicePath(device string) (string, error) {
// the only possible error is ErrBadPattern
return "", err
}

for _, match := range matches {
matchStat, err := os.Stat(match)
if err != nil {
l.Debug("failed to stat match", "match", match, "error", err)

continue
}

if os.SameFile(stat, matchStat) {
l.Debug("match found for device", "match", match, "device", device)

return match, nil
}
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/ephem/swap.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func SwapEntries() ([]*SwapEntry, error) {
if err != nil {
return nil, err
}

devices[idx].Filename = stablePath
}

Expand All @@ -73,6 +74,7 @@ func ReadSwapFile(reader io.Reader) ([]*SwapEntry, error) {
}

var result []*SwapEntry

for scanner.Scan() {
line := scanner.Text()

Expand Down
21 changes: 11 additions & 10 deletions pkg/ephem/swap_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package ephem
package ephem_test

import (
"strings"
"testing"

"github.com/numtide/nixos-facter/pkg/ephem"
"github.com/stretchr/testify/require"
)

Expand All @@ -25,40 +26,40 @@ foo bar baz
func TestReadSwapFile(t *testing.T) {
as := require.New(t)

_, err := ReadSwapFile(strings.NewReader(""))
_, err := ephem.ReadSwapFile(strings.NewReader(""))
as.Error(err, "swaps file is empty")

_, err = ReadSwapFile(strings.NewReader("foo bar baz hello world\n"))
_, err = ephem.ReadSwapFile(strings.NewReader("foo bar baz hello world\n"))
as.Errorf(err, "header in swaps file is malformed: '%s'", "foo bar baz hello world\n")

swaps, err := ReadSwapFile(strings.NewReader(empty))
swaps, err := ephem.ReadSwapFile(strings.NewReader(empty))
as.NoError(err)
as.Empty(swaps)

_, err = ReadSwapFile(strings.NewReader(corrupt))
_, err = ephem.ReadSwapFile(strings.NewReader(corrupt))
as.Errorf(err, "malformed entry in swaps file: '%s'", "foo bar baz")

_, err = ReadSwapFile(strings.NewReader(badPartition))
_, err = ephem.ReadSwapFile(strings.NewReader(badPartition))
as.Errorf(err, "malformed entry in swaps file: '%s'", `/var/lib/swap-1 foo 1048576 123 -3`)

swaps, err = ReadSwapFile(strings.NewReader(sample))
swaps, err = ephem.ReadSwapFile(strings.NewReader(sample))
as.NoError(err)
as.Len(swaps, 3)

as.Equal(swaps[0].Filename, "/dev/sda6")
as.Equal(swaps[0].Type, SwapTypePartition)
as.Equal(swaps[0].Type, ephem.SwapTypePartition)
as.Equal(swaps[0].Size, uint64(4194300))
as.Equal(swaps[0].Used, uint64(0))
as.Equal(swaps[0].Priority, int32(-1))

as.Equal(swaps[1].Filename, "/var/lib/swap-1")
as.Equal(swaps[1].Type, SwapTypeFile)
as.Equal(swaps[1].Type, ephem.SwapTypeFile)
as.Equal(swaps[1].Size, uint64(1048576))
as.Equal(swaps[1].Used, uint64(123))
as.Equal(swaps[1].Priority, int32(-3))

as.Equal(swaps[2].Filename, "/var/lib/swap-2")
as.Equal(swaps[2].Type, SwapTypeFile)
as.Equal(swaps[2].Type, ephem.SwapTypeFile)
as.Equal(swaps[2].Size, uint64(2097152))
as.Equal(swaps[2].Used, uint64(4567))
as.Equal(swaps[2].Priority, int32(-2))
Expand Down
20 changes: 13 additions & 7 deletions pkg/facter/facter.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ package facter
import (
"fmt"

"github.com/numtide/nixos-facter/pkg/ephem"

"github.com/numtide/nixos-facter/pkg/build"
"github.com/numtide/nixos-facter/pkg/ephem"
"github.com/numtide/nixos-facter/pkg/hwinfo"
"github.com/numtide/nixos-facter/pkg/virt"
)
Expand All @@ -27,7 +26,8 @@ type Report struct {
// Hardware provides detailed information about the system’s hardware components, such as CPU, memory, and peripherals.
Hardware Hardware `json:"hardware,omitempty"`

// Smbios provides detailed information about the system's SMBios data, such as BIOS, board, chassis, memory, and processors.
// Smbios provides detailed information about the system's SMBios data, such as BIOS, board, chassis, memory,
// and processors.
Smbios Smbios `json:"smbios,omitempty"`

// Swap contains a list of swap entries representing the system's swap devices or files and their respective details.
Expand All @@ -51,17 +51,21 @@ type Scanner struct {
// It also detects IOMMU groups and handles errors gracefully if scanning fails.
func (s *Scanner) Scan() (*Report, error) {
var err error

report := Report{
Version: build.ReportVersion,
}

if build.System == "" {
return nil, fmt.Errorf("system is not set")
}

report.System = build.System

var smbios []hwinfo.Smbios
var devices []hwinfo.HardwareDevice
var (
smbios []hwinfo.Smbios
devices []hwinfo.HardwareDevice
)

smbios, devices, err = hwinfo.Scan(s.Features)
if err != nil {
Expand All @@ -77,10 +81,12 @@ func (s *Scanner) Scan() (*Report, error) {
for idx := range devices {
// lookup iommu group before adding to the report
device := devices[idx]
groupId, ok := iommuGroups[device.SysfsId]

groupID, ok := iommuGroups[device.SysfsID]
if ok {
device.SysfsIOMMUGroupId = &groupId
device.SysfsIOMMUGroupID = &groupID
}

if err = report.Hardware.add(device); err != nil {
return nil, fmt.Errorf("failed to add to hardware report: %w", err)
}
Expand Down
37 changes: 19 additions & 18 deletions pkg/facter/hardware.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ type Hardware struct {
// ChipCard holds the list of chip card devices in the hardware.
ChipCard []hwinfo.HardwareDevice `json:"chip_card,omitempty"`

// Cpu holds the list of CPU details in the hardware.
// CPU holds the list of CPU details in the hardware.
// There is one entry per physical id.
Cpu []hwinfo.DetailCpu `json:"cpu,omitempty"`
CPU []*hwinfo.DetailCPU `json:"cpu,omitempty"`

// Disk holds the list of disk devices in the hardware.
Disk []hwinfo.HardwareDevice `json:"disk,omitempty"`
Expand Down Expand Up @@ -181,7 +181,7 @@ type Hardware struct {
}

func compareDevice(a hwinfo.HardwareDevice, b hwinfo.HardwareDevice) int {
return int(a.Index - b.Index)
return int(a.Index - b.Index) //nolint:gosec
}

func (h *Hardware) add(device hwinfo.HardwareDevice) error {
Expand All @@ -197,10 +197,10 @@ func (h *Hardware) add(device hwinfo.HardwareDevice) error {
case hwinfo.HardwareClassBios:
if h.Bios != nil {
return fmt.Errorf("bios field is already set")
} else if bios, ok := device.Detail.(hwinfo.DetailBios); !ok {
} else if bios, ok := device.Detail.(*hwinfo.DetailBios); !ok {
return fmt.Errorf("expected hwinfo.DetailBios, found %T", device.Detail)
} else {
h.Bios = &bios
h.Bios = bios
}
case hwinfo.HardwareClassBlockDevice:
h.BlockDevice = append(h.BlockDevice, device)
Expand All @@ -224,22 +224,23 @@ func (h *Hardware) add(device hwinfo.HardwareDevice) error {
h.ChipCard = append(h.ChipCard, device)
slices.SortFunc(h.ChipCard, compareDevice)
case hwinfo.HardwareClassCpu:
cpu, ok := device.Detail.(hwinfo.DetailCpu)
cpu, ok := device.Detail.(*hwinfo.DetailCPU)
if !ok {
return fmt.Errorf("expected hwinfo.DetailCpu, found %T", device.Detail)
return fmt.Errorf("expected hwinfo.DetailCPU, found %T", device.Detail)
}

// We insert by physical id, as we only want one entry per core.
requiredSize := int(cpu.PhysicalId) + 1
if len(h.Cpu) < requiredSize {
newItems := make([]hwinfo.DetailCpu, requiredSize-len(h.Cpu))
h.Cpu = append(h.Cpu, newItems...)
requiredSize := int(cpu.PhysicalID) + 1 //nolint:gosec
if len(h.CPU) < requiredSize {
newItems := make([]*hwinfo.DetailCPU, requiredSize-len(h.CPU))
h.CPU = append(h.CPU, newItems...)
}
h.Cpu[cpu.PhysicalId] = cpu

h.CPU[cpu.PhysicalID] = cpu

// Sort in ascending order to ensure a stable output
slices.SortFunc(h.Cpu, func(a, b hwinfo.DetailCpu) int {
return int(a.PhysicalId - b.PhysicalId)
slices.SortFunc(h.CPU, func(a, b *hwinfo.DetailCPU) int {
return int(a.PhysicalID - b.PhysicalID) //nolint:gosec
})

case hwinfo.HardwareClassDisk:
Expand Down Expand Up @@ -359,10 +360,10 @@ func (h *Hardware) add(device hwinfo.HardwareDevice) error {
case hwinfo.HardwareClassSystem:
if h.System != nil {
return fmt.Errorf("system field is already set")
} else if system, ok := device.Detail.(hwinfo.DetailSys); !ok {
} else if system, ok := device.Detail.(*hwinfo.DetailSys); !ok {
return fmt.Errorf("expected hwinfo.DetailSys, found %T", device.Detail)
} else {
h.System = &system
h.System = system
}
case hwinfo.HardwareClassTape:
h.Tape = append(h.Tape, device)
Expand All @@ -388,8 +389,8 @@ func (h *Hardware) add(device hwinfo.HardwareDevice) error {
case hwinfo.HardwareClassZip:
h.Zip = append(h.Zip, device)
slices.SortFunc(h.Zip, compareDevice)
case hwinfo.HardwareClassAll:
// Do nothing, this is used by the hwinfo cli exclusively.
case hwinfo.HardwareClassAll: // Do nothing, this is used by the hwinfo cli exclusively.
}

return nil
}
Loading

0 comments on commit 5b4a7a8

Please sign in to comment.