1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
package gitpb
// functions to import and export the protobuf
// data to and from config files
import (
"errors"
"os"
"path/filepath"
"time"
"go.wit.com/lib/config"
"go.wit.com/lib/protobuf/bugpb"
"go.wit.com/log"
)
var globalChanged bool
var globalReason string
func (all *Repos) SmartSave() error {
if !globalChanged {
return nil
}
log.Info("saved because", globalReason)
globalChanged = false
globalReason = ""
return all.Save()
}
// write the repos.pb file
func (all *Repos) ConfigSave(fname string) error {
if all == nil {
log.Warn("gitpb repos == nil")
return errors.New("gitpb.ConfigSave() repos == nil")
}
if _, s := filepath.Split(fname); s != "repos.pb" {
log.Infof("ConfigSave() filename '%s' invalid\n", fname)
return log.Errorf("ConfigSave() filename '%s' invalid\n", fname)
}
return all.SaveValidate(fname)
}
// bypass name check "repos.pb"
func (pb *Repos) SaveValidate(fname string) error {
if pb.Filename != fname {
log.Printf("gitpb.Repos.Filename mismatch '%s' != '%s'\n", pb.Filename, fname)
pb.Filename = fname
time.Sleep(5 * time.Second)
}
data, err := pb.Marshal()
if err != nil {
log.Info("gitpb proto.Marshal() failed len", len(data), err)
// often this is because strings have invalid UTF-8. This should probably be fixed in the protobuf code
// this might be fixed in the create code, but it can't hurt to try this as a last ditch effort here
log.Info("gitpb.ConfigSave() ATTEMPTING TO VALIDATE UTF-8 strings in the protobuf file")
if err := pb.tryValidate(); err != nil {
log.Info("gitpb.ConfigSave() STILL FAILEd", err)
return err
} else {
// re-attempt Marshal() here
data, err = pb.Marshal()
if err == nil {
// validate & sanitize strings worked
configWrite(fname, data)
return nil
}
log.Info("gitpb.ConfigSave() STILL FAILEd", err)
}
return err
}
config.Save(pb)
return nil
}
// todo: move this to Marshal() functions automatically in autogenpb?
func (repo *Repo) ValidateUTF8() error {
if _, err := repo.Marshal(); err == nil {
// exit if Marshal() works
return nil
} else {
// log.Printf("%s repo.Marshal() failed: %v\n", repo.GetFullPath(), err)
}
// you only need to do this if Marshal() fails
err := bugpb.ValidateProtoUTF8(repo)
if err != nil {
// log.Printf("Protobuf UTF-8 validation failed: %v\n", err)
}
if err := bugpb.SanitizeProtoUTF8(repo); err != nil {
log.Warn("gitpb.ValidateUTF8()( failed:", err)
return err
}
return nil
}
func (all *Repos) tryValidate() error {
err := bugpb.ValidateProtoUTF8(all)
if err != nil {
log.Printf("Protobuf UTF-8 validation failed: %v\n", err)
}
if err := bugpb.SanitizeProtoUTF8(all); err != nil {
log.Warn("Sanitation failed:", err)
// log.Fatalf("Sanitization failed: %v", err)
return err
}
return nil
}
// load the repos.pb file.
func (all *Repos) ConfigLoad(cfgname string) error {
var data []byte
var err error
if data, err = loadFile(cfgname); err != nil {
// something went wrong loading the file
// all.sampleConfig() // causes nil panic
log.Info("Repos ConfigLoad() failed", cfgname, err)
return err
}
// this means the forge.pb file exists and was read
if len(data) == 0 {
return errors.New("gitpb.ConfigLoad() repos.pb is empty")
}
err = all.Unmarshal(data)
test := NewRepos()
if test.Uuid != all.Uuid {
log.Log(WARN, "uuids do not match", test.Uuid, all.Uuid)
deleteProtobufFile(cfgname)
}
if test.Version != all.Version {
log.Log(WARN, "versions do not match", test.Version, all.Version)
deleteProtobufFile(cfgname)
}
log.Log(INFO, cfgname, "protobuf versions and uuid match", all.Uuid, all.Version)
return err
}
func deleteProtobufFile(filename string) {
log.Log(WARN, "The protobuf file format has changed for", filename)
log.Log(WARN, "Deleting old file:", filename)
log.Log(WARN, "This file will be recreated on the next run.")
err := os.Remove(filename)
if err != nil {
log.Log(WARN, "failed to remove old protobuf file", "err", err)
}
}
func (all *Repos) sampleConfig() {
newr := new(Repo)
newr.FullPath = "/opt/forge/dummyentry"
all.Append(newr)
}
func loadFile(fullname string) ([]byte, error) {
data, err := os.ReadFile(fullname)
if errors.Is(err, os.ErrNotExist) {
// the file does not exist
return nil, err
}
if err != nil {
log.Info(fullname, "permission error? error =", err)
return nil, err
}
return data, nil
}
func configWrite(fullname string, data []byte) error {
log.Infof("%s your repos have changed state. cached state. (%d) bytes\n", fullname, len(data))
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
}
|