summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2025-09-10 14:45:55 -0500
committerJeff Carr <[email protected]>2025-09-10 14:45:55 -0500
commitc0a3642ed20451dff7670babc1c500ec5c847d51 (patch)
tree1d2e293a5f7dfb299092c94e0dd97af70fe425fd
parenteda66a77b689e25918aad16350231abaefad9ac4 (diff)
add generic ConfigLoad()
-rw-r--r--findFilename.go70
-rw-r--r--load.go63
-rw-r--r--save.go50
3 files changed, 180 insertions, 3 deletions
diff --git a/findFilename.go b/findFilename.go
new file mode 100644
index 0000000..d69b538
--- /dev/null
+++ b/findFilename.go
@@ -0,0 +1,70 @@
+package config
+
+import (
+ "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/reflect/protoreflect"
+)
+
+// Gemini AI can help author some pretty good protobuf code.
+// I never remember the syntax for 'reflect' on these things.
+
+// returns "Filename" if it exists in the protobuf
+func GetFilename(pb proto.Message) (string, bool) {
+ // 1. Get the protoreflect.Message interface from the message.
+ // This is the entry point to the reflection API.
+ msg := pb.ProtoReflect()
+
+ // 2. Get the message's descriptor, which contains metadata about its fields.
+ descriptor := msg.Descriptor()
+
+ // 3. Find the specific field descriptor by its protobuf name ("Filename").
+ // Note: The field name must match the name in the .proto file.
+ fieldName := protoreflect.Name("Filename")
+ fieldDescriptor := descriptor.Fields().ByName(fieldName)
+
+ // 4. Check if the field was found. If not, return false.
+ if fieldDescriptor == nil {
+ return "", false
+ }
+
+ // 5. (Optional but recommended) Verify the field is a string type.
+ if fieldDescriptor.Kind() != protoreflect.StringKind {
+ // The field exists but is not a string, so we can't return it as one.
+ return "", false
+ }
+
+ // 6. If the field exists and is a string, get its value.
+ // The value is returned as a protoreflect.Value.
+ value := msg.Get(fieldDescriptor)
+
+ // 7. Convert the protoreflect.Value to a native Go string.
+ return value.String(), true
+}
+
+// sets "Filename" if it exists in the protobuf
+func SetFilename(pb proto.Message, filename string) bool {
+ msg := pb.ProtoReflect() // This is the entry point to the reflection API.
+
+ descriptor := msg.Descriptor() // Get the message's descriptor, which contains metadata about its fields.
+
+ fieldName := protoreflect.Name("Filename")
+ fieldDescriptor := descriptor.Fields().ByName(fieldName)
+
+ if fieldDescriptor == nil {
+ return false
+ }
+
+ if fieldDescriptor.Kind() != protoreflect.StringKind {
+ // The field exists but is not a string, so we can't return it as one.
+ return false
+ }
+
+ valueToSet := protoreflect.ValueOfString(filename)
+
+ // 6. If the field exists and is a string, get its value.
+ // The value is returned as a protoreflect.Value.
+ msg.Set(fieldDescriptor, valueToSet)
+
+ // 7. Convert the protoreflect.Value to a native Go string.
+ return true
+}
diff --git a/load.go b/load.go
index 31e169a..1568968 100644
--- a/load.go
+++ b/load.go
@@ -1,14 +1,71 @@
package config
+// functions to import and export the protobuf
+// data to and from config files
+
import (
+ "errors"
"os"
- "strings"
- "unicode"
+ "path/filepath"
"go.wit.com/log"
- "golang.org/x/term"
+ "google.golang.org/protobuf/encoding/prototext"
+ "google.golang.org/protobuf/proto"
)
+/*
// loads a file from ~/.config/<argname>/
func Load(argname string) ([]byte, string) {
}
+*/
+
+var ErrEmpty error = log.Errorf("file was empty")
+
+// returns:
+// - Full path to the config file. usually: ~/.config/<argname>
+// - []byte : the contents of the file
+// - error on read
+func ConfigLoad(pb proto.Message, argname string, protoname string) error {
+ var data []byte
+ var fullname string
+ homeDir, err := os.UserHomeDir()
+ if err != nil {
+ return err
+ }
+
+ fullname = filepath.Join(homeDir, ".config", argname, protoname+".text")
+ if data, err = loadFile(fullname); err != nil {
+ log.Warn("config file failed to load", err)
+ // something went wrong loading the file
+ return err
+ }
+
+ // don't even bother with Marshal()
+ if data == nil {
+ return ErrEmpty // file is empty
+ }
+
+ // Unmarshal()
+ if err = prototext.Unmarshal(data, pb); err != nil {
+ return err
+ }
+
+ // set pb.Filename if it is there in the .proto file
+ SetFilename(pb, fullname)
+
+ log.Infof("ConfigLoad() arg=%s, proto=%s\n", argname, protoname)
+ return nil
+}
+
+func loadFile(fullname string) ([]byte, error) {
+ data, err := os.ReadFile(fullname)
+ if errors.Is(err, os.ErrNotExist) {
+ // if file does not exist, just return nil. this
+ return nil, err
+ }
+ if err != nil {
+ // log.Info("open config file :", err)
+ return nil, err
+ }
+ return data, nil
+}
diff --git a/save.go b/save.go
new file mode 100644
index 0000000..35c5bab
--- /dev/null
+++ b/save.go
@@ -0,0 +1,50 @@
+package config
+
+// functions to import and export the protobuf
+// data to and from config files
+
+/*
+
+func (e *Events) Save() {
+ var fullname string
+ base, _ := filepath.Split(argv.Config)
+ fullname = filepath.Join(base, "events.pb")
+
+ data, err := e.Marshal()
+ if err != nil {
+ log.Info("proto.Marshal() failed", err)
+ return
+ }
+ log.Info("proto.Marshal() worked len", len(data))
+ configWrite(fullname, data)
+}
+
+
+func configWrite(fullname string, data []byte) error {
+ if _, base := filepath.Split(fullname); base == "" {
+ return fmt.Errorf("--config option not set")
+ }
+ cfgfile, err := os.OpenFile(fullname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
+ defer cfgfile.Close()
+ if err != nil {
+ log.Warn("open config file :", err)
+ return err
+ }
+ cfgfile.Write(data)
+ return nil
+}
+
+func (m *Portmaps) configWrite(fullname string, data []byte) error {
+ if _, base := filepath.Split(fullname); base == "" {
+ return fmt.Errorf("--config option not set")
+ }
+ cfgfile, err := os.OpenFile(fullname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
+ defer cfgfile.Close()
+ if err != nil {
+ log.Warn("open config file :", err)
+ return err
+ }
+ cfgfile.Write(data)
+ return nil
+}
+*/