Add MacOS support, replace sysinfo #1
15 changed files with 262 additions and 44 deletions
|
@ -7,7 +7,7 @@ distribution artwork should be:
|
||||||
- line drawings, not filled
|
- line drawings, not filled
|
||||||
- close to 8 lines long and square-ish
|
- close to 8 lines long and square-ish
|
||||||
|
|
||||||
they are plain text files stored under `artwork/`. the file name should be the `OS.Vendor` value in the struct returned by [zcalusic/sysinfo](https://github.com/zcalusic/sysinfo).
|
they are plain text files stored under `artwork/`. the file name should be the `OS.Vendor` value in the struct returned by [modules/os](modules/os).
|
||||||
|
|
||||||
### platform compliance
|
### platform compliance
|
||||||
i am just one person: a linux user without much access to commercial/esoteric OSes or a variety of hardware; so i would like help with testing and tailoring to work on as many computers as possible. of course it's not going to work on *literally every machine*, but reasonably common ones are my general target.
|
i am just one person: a linux user without much access to commercial/esoteric OSes or a variety of hardware; so i would like help with testing and tailoring to work on as many computers as possible. of course it's not going to work on *literally every machine*, but reasonably common ones are my general target.
|
||||||
|
|
|
@ -6,9 +6,9 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"git.cyberia.club/reese/mewfetch/modules"
|
||||||
"git.cyberia.club/reese/slog"
|
"git.cyberia.club/reese/slog"
|
||||||
"github.com/mattn/go-runewidth"
|
"github.com/mattn/go-runewidth"
|
||||||
"github.com/zcalusic/sysinfo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed artwork
|
//go:embed artwork
|
||||||
|
@ -50,10 +50,7 @@ func draw() {
|
||||||
artName = "custom"
|
artName = "custom"
|
||||||
artwork = conf.Custom
|
artwork = conf.Custom
|
||||||
} else if conf.OS == "auto" {
|
} else if conf.OS == "auto" {
|
||||||
var si sysinfo.SysInfo
|
artwork = getArt(modules.GetOSVendor())
|
||||||
si.GetSysInfo()
|
|
||||||
artName = si.OS.Vendor
|
|
||||||
artwork = getArt(artName)
|
|
||||||
} else {
|
} else {
|
||||||
artName = conf.OS
|
artName = conf.OS
|
||||||
artwork = getArt(artName)
|
artwork = getArt(artName)
|
||||||
|
|
7
artwork/apple
Normal file
7
artwork/apple
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
.:'
|
||||||
|
__ :'__
|
||||||
|
.`` `-' ``.
|
||||||
|
: .`
|
||||||
|
: `._
|
||||||
|
: ;
|
||||||
|
`.__.-.__.`
|
2
go.mod
2
go.mod
|
@ -6,7 +6,6 @@ toolchain go1.22.8
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
|
||||||
github.com/kr/pretty v0.1.0 // indirect
|
github.com/kr/pretty v0.1.0 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
@ -23,6 +22,5 @@ require (
|
||||||
github.com/mackerelio/go-osstat v0.2.5
|
github.com/mackerelio/go-osstat v0.2.5
|
||||||
github.com/mattn/go-runewidth v0.0.16
|
github.com/mattn/go-runewidth v0.0.16
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/zcalusic/sysinfo v1.1.3
|
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -7,8 +7,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
@ -33,8 +31,6 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/zcalusic/sysinfo v1.1.3 h1:u/AVENkuoikKuIZ4sUEJ6iibpmQP6YpGD8SSMCrqAF0=
|
|
||||||
github.com/zcalusic/sysinfo v1.1.3/go.mod h1:NX+qYnWGtJVPV0yWldff9uppNKU4h40hJIRPf/pGLv4=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||||
|
|
|
@ -1,23 +1,14 @@
|
||||||
package modules
|
package modules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"git.cyberia.club/reese/slog"
|
"git.cyberia.club/reese/slog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CPU(opts map[string]string) (rune, string) {
|
func CPU(opts map[string]string) (rune, string) {
|
||||||
var model_name string
|
model_name, err := getCPUModelName()
|
||||||
switch runtime.GOOS {
|
if err != nil {
|
||||||
case "linux":
|
slog.Warn(err, "could not get CPU model name")
|
||||||
meminfo, err := os.ReadFile("/proc/cpuinfo")
|
return '', "Unknown"
|
||||||
slog.Warn(err, "module: memory: unable to read /proc/meminfo")
|
|
||||||
|
|
||||||
model_name = regexp.MustCompile(`model name\s*:\s*(\w.*)`).FindStringSubmatch(string(meminfo))[1]
|
|
||||||
}
|
}
|
||||||
// TODO: more OS cases
|
|
||||||
|
|
||||||
return '', model_name
|
return '', model_name
|
||||||
}
|
}
|
||||||
|
|
12
modules/cpu_darwin.go
Normal file
12
modules/cpu_darwin.go
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
//go:build darwin
|
||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package modules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getCPUModelName() (string, error) {
|
||||||
|
return unix.Sysctl("machdep.cpu.brand_string")
|
||||||
|
}
|
21
modules/cpu_linux.go
Normal file
21
modules/cpu_linux.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
//go:build linux
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package modules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getCPUModelName() (string, error) {
|
||||||
|
cpuinfo, err := os.ReadFile("/proc/cpuinfo")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
matches := regexp.MustCompile(`model name\s*:\s*(\w.*)`).FindStringSubmatch(string(cpuinfo))
|
||||||
|
if len(matches) < 2 {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return matches[1], nil
|
||||||
|
}
|
|
@ -2,25 +2,15 @@ package modules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"git.cyberia.club/reese/slog"
|
"git.cyberia.club/reese/slog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Memory(opts map[string]string) (rune, string) {
|
func Memory(opts map[string]string) (rune, string) {
|
||||||
var memory int
|
memory, err := getMemory()
|
||||||
switch runtime.GOOS {
|
if err != nil {
|
||||||
case "linux":
|
slog.Warn(err, "module: memory: unable to get memory")
|
||||||
meminfo, err := os.ReadFile("/proc/meminfo")
|
return '', "Unknown"
|
||||||
slog.Warn(err, "module: memory: unable to read /proc/meminfo")
|
|
||||||
|
|
||||||
memory, err = strconv.Atoi(regexp.MustCompile(`MemTotal:\s+(\d+)`).FindStringSubmatch(string(meminfo))[1])
|
|
||||||
memory *= 1000
|
|
||||||
}
|
}
|
||||||
// TODO: more OS cases
|
|
||||||
|
|
||||||
return '', fmt.Sprintf("%s", byteFormat(memory))
|
return '', fmt.Sprintf("%s", byteFormat(memory))
|
||||||
}
|
}
|
||||||
|
|
19
modules/memory_darwin.go
Normal file
19
modules/memory_darwin.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
//go:build darwin
|
||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package modules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getMemory() (int, error) {
|
||||||
|
totalb, err := unix.Sysctl("hw.memsize")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
mem := int(binary.LittleEndian.Uint64([]byte(totalb + "\x00")))
|
||||||
|
return mem, nil
|
||||||
|
}
|
29
modules/memory_linux.go
Normal file
29
modules/memory_linux.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//go:build linux
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package modules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getMemory() (int, error) {
|
||||||
|
meminfo, err := os.ReadFile("/proc/meminfo")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
matches := regexp.MustCompile(`MemTotal:\s+(\d+)`).FindStringSubmatch(string(meminfo))
|
||||||
|
if len(matches) < 2 {
|
||||||
|
return 0, errors.New("could not find MemTotal in /proc/meminfo")
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := strconv.Atoi(matches[1])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return val * 1000, nil
|
||||||
|
}
|
|
@ -3,20 +3,44 @@ package modules
|
||||||
import (
|
import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/zcalusic/sysinfo"
|
"git.cyberia.club/reese/slog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type OSInfo struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Vendor string `json:"vendor,omitempty"`
|
||||||
|
Version string `json:"version,omitempty"`
|
||||||
|
Release string `json:"release,omitempty"`
|
||||||
|
Architecture string `json:"architecture,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
func OS(opts map[string]string) (rune, string) {
|
func OS(opts map[string]string) (rune, string) {
|
||||||
var si sysinfo.SysInfo
|
osInfo, err := getOSInfo()
|
||||||
si.GetSysInfo()
|
if err != nil {
|
||||||
|
slog.Warn(err, "module: os: unable to get OS info")
|
||||||
|
return '', "Unknown"
|
||||||
|
}
|
||||||
|
|
||||||
icon := map[string]rune{
|
icon := map[string]rune{
|
||||||
"linux": '',
|
"linux": '',
|
||||||
"macos": '',
|
"darwin": '',
|
||||||
"windows": '',
|
"windows": '',
|
||||||
"freebsd": '',
|
"freebsd": '',
|
||||||
"openbsd": '',
|
"openbsd": '',
|
||||||
}[runtime.GOOS]
|
}[runtime.GOOS]
|
||||||
|
|
||||||
return icon, si.OS.Name
|
if icon == 0 {
|
||||||
|
icon = '' // default to Linux icon if unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
return icon, osInfo.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetOSVendor() string {
|
||||||
|
os, err := getOSInfo()
|
||||||
|
if err != nil {
|
||||||
|
slog.Warn(err, "module: os: unable to get OS info")
|
||||||
|
return "Unknown"
|
||||||
|
}
|
||||||
|
return os.Vendor
|
||||||
}
|
}
|
||||||
|
|
25
modules/os_darwin.go
Normal file
25
modules/os_darwin.go
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
//go:build darwin
|
||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package modules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getOSInfo() (*OSInfo, error) {
|
||||||
|
OS := &OSInfo{}
|
||||||
|
OS.Name = "macOS"
|
||||||
|
OS.Vendor = "apple"
|
||||||
|
|
||||||
|
// Get architecture using `uname -m`
|
||||||
|
cmd := exec.Command("uname", "-m")
|
||||||
|
stdout, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
OS.Architecture = strings.TrimSpace(string(stdout))
|
||||||
|
|
||||||
|
return OS, nil
|
||||||
|
}
|
99
modules/os_linux.go
Normal file
99
modules/os_linux.go
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
//go:build linux
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package modules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
rePrettyName = regexp.MustCompile(`^PRETTY_NAME=(.*)$`)
|
||||||
|
reID = regexp.MustCompile(`^ID=(.*)$`)
|
||||||
|
reVersionID = regexp.MustCompile(`^VERSION_ID=(.*)$`)
|
||||||
|
reUbuntu = regexp.MustCompile(`[\( ]([\d\.]+)`)
|
||||||
|
reAlma = regexp.MustCompile(`^AlmaLinux release ([\d\.]+)`)
|
||||||
|
reCentOS = regexp.MustCompile(`^CentOS( Linux)? release ([\d\.]+)`)
|
||||||
|
reRocky = regexp.MustCompile(`^Rocky Linux release ([\d\.]+)`)
|
||||||
|
reRedHat = regexp.MustCompile(`[\( ]([\d\.]+)`)
|
||||||
|
)
|
||||||
|
|
||||||
|
func getOSInfo() (*OSInfo, error) {
|
||||||
|
OS := &OSInfo{}
|
||||||
|
|
||||||
|
// Get architecture using `uname -m`
|
||||||
|
cmd := exec.Command("uname", "-m")
|
||||||
|
stdout, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return OS, err
|
||||||
|
}
|
||||||
|
OS.Architecture = strings.TrimSpace(string(stdout))
|
||||||
|
|
||||||
|
f, err := os.Open("/etc/os-release")
|
||||||
|
if err != nil {
|
||||||
|
return OS, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
s := bufio.NewScanner(f)
|
||||||
|
for s.Scan() {
|
||||||
|
line := s.Text()
|
||||||
|
if m := rePrettyName.FindStringSubmatch(line); m != nil {
|
||||||
|
OS.Name = strings.Trim(m[1], `"`)
|
||||||
|
} else if m := reID.FindStringSubmatch(line); m != nil {
|
||||||
|
OS.Vendor = strings.Trim(m[1], `"`)
|
||||||
|
} else if m := reVersionID.FindStringSubmatch(line); m != nil {
|
||||||
|
OS.Version = strings.Trim(m[1], `"`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch OS.Vendor {
|
||||||
|
case "debian":
|
||||||
|
OS.Release = slurpFile("/etc/debian_version")
|
||||||
|
case "ubuntu":
|
||||||
|
if m := reUbuntu.FindStringSubmatch(OS.Name); m != nil {
|
||||||
|
OS.Release = m[1]
|
||||||
|
}
|
||||||
|
case "almalinux":
|
||||||
|
if release := slurpFile("/etc/almalinux-release"); release != "" {
|
||||||
|
if m := reAlma.FindStringSubmatch(release); m != nil {
|
||||||
|
OS.Release = m[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if OS.Release != "" {
|
||||||
|
OS.Version = strings.Split(OS.Release, ".")[0]
|
||||||
|
}
|
||||||
|
case "centos":
|
||||||
|
if release := slurpFile("/etc/centos-release"); release != "" {
|
||||||
|
if m := reCentOS.FindStringSubmatch(release); m != nil {
|
||||||
|
OS.Release = m[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "rocky":
|
||||||
|
if release := slurpFile("/etc/rocky-release"); release != "" {
|
||||||
|
if m := reRocky.FindStringSubmatch(release); m != nil {
|
||||||
|
OS.Release = m[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if OS.Release != "" {
|
||||||
|
OS.Version = strings.Split(OS.Release, ".")[0]
|
||||||
|
}
|
||||||
|
case "rhel":
|
||||||
|
if release := slurpFile("/etc/redhat-release"); release != "" {
|
||||||
|
if m := reRedHat.FindStringSubmatch(release); m != nil {
|
||||||
|
OS.Release = m[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if OS.Release == "" {
|
||||||
|
if m := reRedHat.FindStringSubmatch(OS.Name); m != nil {
|
||||||
|
OS.Release = m[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OS, nil
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package modules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -64,3 +65,12 @@ func durationStr(d time.Duration) string {
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// slurpFile reads a file and trims whitespace.
|
||||||
|
func slurpFile(path string) string {
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return strings.Trim(string(data), " \r\n\t\u0000\uffff")
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue