diff --git a/Makefile b/Makefile index 5ea91ac..65d1dc9 100644 --- a/Makefile +++ b/Makefile @@ -3,14 +3,16 @@ GUIVERSION = $(shell git describe --tags) BUILDTIME = $(shell date +%Y.%m.%d) all: verbose - ./fixup drives + -fixup --gui-check-plugin ../../../toolkits/gocui/gocui.so + fixup --gui gocui --gui-verbose --gui-file ../../toolkits/gocui/gocui.so drives go-build: goimports GO111MODULE=off go build \ -ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}" verbose: goimports - GO111MODULE=off go build -v -x \ + -cp -a ../../../toolkits/gocui/gocui.so resources/ + GO111MODULE=off go install -v -x \ -ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}" install: goimports diff --git a/argv.go b/argv.go index fc7fc7b..bea917b 100644 --- a/argv.go +++ b/argv.go @@ -59,5 +59,5 @@ func init() { } func (args) Version() string { - return "wit-test " + VERSION + " Built on " + BUILDTIME + return ARGNAME + " " + VERSION + " Built on " + BUILDTIME } diff --git a/argvAutocomplete.go b/argvAutocomplete.go index 9d60ceb..bbedb83 100644 --- a/argvAutocomplete.go +++ b/argvAutocomplete.go @@ -13,9 +13,6 @@ import ( handles shell autocomplete */ -// used for shell auto completion -var ARGNAME string = "wit-test" // todo: get this from $0 ? - func (args) doBashAuto() { argv.doBashHelp() switch argv.BashAuto[0] { @@ -68,6 +65,8 @@ func (args) doBash() { fmt.Println("") fmt.Println("# todo: add this to go-arg as a 'hidden' go-arg option --bash") fmt.Println("#") + fmt.Println("# Put the below in the file: ~/.local/share/bash-completion/completions/" + ARGNAME) + fmt.Println("#") fmt.Println("# todo: make this output work/parse with:") fmt.Println("# complete -C " + ARGNAME + " --bash go") fmt.Println("") diff --git a/doDrives.go b/doDrives.go index bc22dae..a1e0b91 100644 --- a/doDrives.go +++ b/doDrives.go @@ -2,7 +2,6 @@ package main import ( "bufio" - "fmt" "io/fs" "os" "path/filepath" @@ -18,7 +17,7 @@ func doDrives() { } for _, p := range parts { - fmt.Printf("Device: /dev/%s\tSize: %d KiB\n", p.Name, p.Blocks) + log.Printf("Device: /dev/%s\tSize: %d KiB\n", p.Name, p.Blocks) } blockDir := "/sys/block" @@ -33,7 +32,7 @@ func doDrives() { if d.IsDir() && filepath.Dir(path) == blockDir { dev := d.Name() devPath := "/dev/" + dev - fmt.Printf("Drive: %s\n", devPath) + log.Printf("Drive: %s\n", devPath) // Look for partitions partitions, err := filepath.Glob(filepath.Join(blockDir, dev, dev+"*")) @@ -51,18 +50,18 @@ func doDrives() { hasPartition = true partDev := "/dev/" + partName isMounted := mounts[partDev] - fmt.Printf(" Partition: %s [%v]\n", partDev, isMounted) + log.Printf(" Partition: %s [%v]\n", partDev, isMounted) if isMounted { used = true } } if !hasPartition { - fmt.Println(" No partitions found.") + log.Println(" No partitions found.") } if !used { - fmt.Println(" → Drive appears to be unused.") + log.Println(" → Drive appears to be unused.") } } return nil @@ -127,9 +126,9 @@ func parseProcPartitions() ([]Partition, error) { } var p Partition - _, err := fmt.Sscanf(line, "%d %d %d %s", &p.Major, &p.Minor, &p.Blocks, &p.Name) + _, err := log.Sscanf(line, "%d %d %d %s", &p.Major, &p.Minor, &p.Blocks, &p.Name) if err != nil { - return nil, fmt.Errorf("error parsing line: %q: %w", line, err) + return nil, log.Errorf("error parsing line: %q: %w", line, err) } partitions = append(partitions, p) } diff --git a/doGui.go b/doGui.go new file mode 100644 index 0000000..fc6fe53 --- /dev/null +++ b/doGui.go @@ -0,0 +1,71 @@ +// Copyright 2017-2025 WIT.COM Inc. All rights reserved. +// Use of this source code is governed by the GPL 3.0 + +package main + +// An app to submit patches for the 30 GO GUI repos + +import ( + "os" + "time" + + "go.wit.com/gui" + "go.wit.com/lib/gadgets" + "go.wit.com/log" +) + +func debug() { + for { + time.Sleep(3 * time.Second) + log.Info("TODO: use this?") + } +} + +func doGui() { + me.myGui = gui.New() + me.myGui.InitEmbed(resources) + me.myGui.Default() + + mainWindow := gadgets.NewGenericWindow("RiscV Imager", "Show Drives") + mainWindow.Custom = func() { + log.Warn("Main window close") + os.Exit(0) + } + + drawWindow(mainWindow) + + // sits here forever + debug() +} + +func drawWindow(win *gadgets.GenericWindow) { + grid := win.Group.RawGrid() + + grid.NewLabel("Drives:") + + me.dd = grid.NewDropdown() + me.dd.AddText("/dev/blah") + me.dd.Custom = func() { + log.Info("todo: changed drive") + } + grid.NextRow() + + grid.NewButton("doDrives()", func() { + doDrives() + }) + + grid.NewButton("doDrives2()", func() { + doDrives2() + }) + + grid.NewButton("partition drives", func() { + log.Info("something") + }) + + grid.NextRow() + + grid.NewButton("ConfigSave()", func() { + log.Info("todo: make code for this") + }) + +} diff --git a/getDrives.go b/getDrives.go index 35e4f49..a818645 100644 --- a/getDrives.go +++ b/getDrives.go @@ -1,10 +1,11 @@ package main import ( - "fmt" "os" "path/filepath" "strings" + + "go.wit.com/log" ) type DevInfo struct { @@ -17,7 +18,7 @@ type DevInfo struct { func doDrives2() { parts, err := parseProcPartitions() if err != nil { - fmt.Fprintf(os.Stderr, "Error reading /proc/partitions: %v\n", err) + log.Printf("Error reading /proc/partitions: %v\n", err) os.Exit(1) } @@ -42,12 +43,14 @@ func doDrives2() { for _, info := range devs { devPath := "/dev/" + info.Name if info.IsRaw { - fmt.Printf("%-12s -> %-8s (raw)\n", devPath, info.Type) + s := log.Sprintf("%-12s -> %-8s (raw)", devPath, info.Type) + log.Info(s) + me.dd.AddText(s) } else { if info.Parent != "" { - fmt.Printf("%-12s -> partition of /dev/%s\n", devPath, info.Parent) + log.Printf("%-12s -> partition of /dev/%s\n", devPath, info.Parent) } else { - fmt.Printf("%-12s -> unknown (no parent found)\n", devPath) + log.Printf("%-12s -> unknown (no parent found)\n", devPath) } } } diff --git a/main.go b/main.go index bd6833d..1a5be65 100644 --- a/main.go +++ b/main.go @@ -5,12 +5,16 @@ package main import ( "debug/buildinfo" + "embed" "fmt" "os" + "os/exec" "path/filepath" + "plugin" "unicode" "go.wit.com/dev/alexflint/arg" + "go.wit.com/gui" "go.wit.com/log" ) @@ -18,9 +22,16 @@ import ( var VERSION string var BUILDTIME string +// used for shell auto completion +var ARGNAME string = "fixup" // todo: get this from $0 ? + +//go:embed resources/* +var resources embed.FS + func main() { me = new(autoType) - me.argpp = arg.MustParse(&argv) + gui.InitArg() + me.pp = arg.MustParse(&argv) if argv.Bash { argv.doBash() @@ -31,12 +42,21 @@ func main() { os.Exit(0) } - if argv.Drives != nil { - doDrives() - doDrives2() - } + // checkPlug("../../../toolkits/gocui/gocui.so") + // checkPlug("/usr/lib/go-gui-toolkits/gocui.v0.22.46.so") - listenForBlockEvents() + /* + if argv.Drives != nil { + doDrives() + doDrives2() + } + */ + + // doDrives() + // okExit("everything compiled") + + go listenForBlockEvents() + doGui() okExit("everything compiled") } @@ -71,26 +91,57 @@ func dumpDebug() { // Get absolute path of the currently running binary exePath, err := os.Executable() if err != nil { - fmt.Println("Error getting executable path:", err) + log.Println("Error getting executable path:", err) return } // Resolve symlinks if necessary exePath, err = filepath.EvalSymlinks(exePath) if err != nil { - fmt.Println("Error resolving symlink:", err) + log.Println("Error resolving symlink:", err) return } // Read build info bi, err := buildinfo.ReadFile(exePath) if err != nil { - fmt.Println("Error reading build info:", err) + log.Println("Error reading build info:", err) return } - fmt.Println("Go Version:", bi.GoVersion) + log.Println("Go Version:", bi.GoVersion) for _, dep := range bi.Deps { - fmt.Printf("Dependency: %s %s\n", dep.Path, dep.Version) + log.Printf("Dependency: %s %s\n", dep.Path, dep.Version) } } + +func checkPlug(pluginPath string) *plugin.Plugin { + if err := checkPluginViaSubprocess(pluginPath); err != nil { + fmt.Printf("Plugin check failed: %v\n", err) + return nil + } + + p, err := plugin.Open(pluginPath) + if err != nil { + log.Fatalf("plugin.Open failed: %v", err) + } + + log.Println("Plugin loaded successfully.") + return p +} + +func checkPluginViaSubprocess(path string) error { + exe, err := os.Executable() + if err != nil { + return fmt.Errorf("failed to get executable path: %w", err) + } + resolved, err := filepath.EvalSymlinks(exe) + if err != nil { + return fmt.Errorf("failed to resolve executable symlink: %w", err) + } + + cmd := exec.Command(resolved, "--gui-check-plugin", path) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} diff --git a/plugincheck/check.go b/plugincheck/check.go new file mode 100644 index 0000000..8d3b683 --- /dev/null +++ b/plugincheck/check.go @@ -0,0 +1,47 @@ +package plugincheck + +import ( + "debug/buildinfo" + "errors" + "fmt" + "runtime/debug" +) + +// CheckPluginCompatibility verifies that the plugin .so file was built +// with the same Go version and dependency versions as the host binary. +func CheckPluginCompatibility(pluginPath string) error { + pluginInfo, err := buildinfo.ReadFile(pluginPath) + if err != nil { + return fmt.Errorf("failed to read plugin build info: %w", err) + } + + mainInfo, ok := debug.ReadBuildInfo() + if !ok { + return errors.New("failed to read main binary build info") + } + + if pluginInfo.GoVersion != mainInfo.GoVersion { + return fmt.Errorf("Go version mismatch: plugin=%s, host=%s", + pluginInfo.GoVersion, mainInfo.GoVersion) + } + + // Create a map of main binary dependencies for quick lookup + hostDeps := make(map[string]string) + for _, dep := range mainInfo.Deps { + hostDeps[dep.Path] = dep.Version + } + + // Compare plugin dependencies + for _, dep := range pluginInfo.Deps { + hostVer, ok := hostDeps[dep.Path] + if !ok { + return fmt.Errorf("dependency %s not found in host binary", dep.Path) + } + if dep.Version != hostVer { + return fmt.Errorf("dependency version mismatch for %s: plugin=%s, host=%s", + dep.Path, dep.Version, hostVer) + } + } + + return nil +} diff --git a/resources/README b/resources/README new file mode 100644 index 0000000..09d5ea4 --- /dev/null +++ b/resources/README @@ -0,0 +1 @@ +put the GO GUI plugin .so files here diff --git a/resources/gocui.so b/resources/gocui.so new file mode 100644 index 0000000..df8357e Binary files /dev/null and b/resources/gocui.so differ diff --git a/structs.go b/structs.go index 50e3742..d76a1ff 100644 --- a/structs.go +++ b/structs.go @@ -5,11 +5,14 @@ package main import ( "go.wit.com/dev/alexflint/arg" + "go.wit.com/gui" ) var me *autoType // this app's variables type autoType struct { - argpp *arg.Parser // go-arg preprocessor + pp *arg.Parser // go-arg preprocessor + myGui *gui.Node // the gui toolkit handle + dd *gui.Node // the drives dropdown list } diff --git a/watchForNewDrives.go b/watchForNewDrives.go index 74b2efe..78b2954 100644 --- a/watchForNewDrives.go +++ b/watchForNewDrives.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "log" "syscall" ) @@ -43,7 +42,7 @@ func listenForBlockEvents() { msg := parseUevent(buf[:n]) if msg["SUBSYSTEM"] == "block" && msg["ACTION"] == "add" { - fmt.Printf("New block device added: %s\n", msg["DEVNAME"]) + log.Printf("New block device added: %s\n", msg["DEVNAME"]) } } }