Skip to content

Commit ac4c9b3

Browse files
committed
Merge branch 'release/0.1.2'
2 parents 4997111 + ff907cc commit ac4c9b3

File tree

4 files changed

+141
-18
lines changed

4 files changed

+141
-18
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
/vers
2+
/cscope.files
3+
/cscope.out

cmd/undo.go

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright © 2020 Robert B Gordon <[email protected]>
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
package cmd
22+
23+
import (
24+
"fmt"
25+
26+
"github.com/apex/log"
27+
"github.com/rbg/vers/ventry"
28+
"github.com/spf13/cobra"
29+
"github.com/spf13/viper"
30+
)
31+
32+
// undoCmd represents the undo command
33+
var undoCmd = &cobra.Command{
34+
Use: "undo",
35+
Short: "Undo last set or bump for entry",
36+
Long: "Undo last set or bump for entry",
37+
Args: func(cmd *cobra.Command, args []string) error {
38+
if viper.GetBool(DEBUG) {
39+
log.SetLevel(log.DebugLevel)
40+
}
41+
if len(viper.GetString(VFILE)) == 0 {
42+
return fmt.Errorf("you must supply the .json or .yaml version file pathname (--%s)", VFILE)
43+
}
44+
if len(viper.GetString(ENTRY)) == 0 {
45+
return fmt.Errorf("you must supply the entry name (--%s)", ENTRY)
46+
}
47+
return nil
48+
},
49+
Run: undo,
50+
}
51+
52+
func init() {
53+
RootCmd.AddCommand(undoCmd)
54+
}
55+
56+
func undo(cmd *cobra.Command, args []string) {
57+
58+
vp, err := ventry.Open(viper.GetString(VFILE), false)
59+
if err != nil {
60+
log.Fatalf("Open failed on %s; %s", viper.GetString(VFILE), err)
61+
}
62+
defer vp.Close()
63+
if err = vp.Undo(viper.GetString(ENTRY)); err != nil {
64+
log.Infof("Undo failed on %s; %s", viper.GetString(VFILE), err)
65+
return
66+
}
67+
vp.Print(viper.GetString(ENTRY), "str")
68+
}

ventry/file.go

+59-17
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import (
3838
)
3939

4040
// writeVersionFile updates the version file info
41-
func writeVersionFile(path string, info *Entries) error {
41+
func writeVersionFile(path string, info *VFile) error {
4242
var bytes []byte
4343

4444
log.Debugf("writeVersionFile: %+#v", info)
@@ -73,8 +73,9 @@ func writeVersionFile(path string, info *Entries) error {
7373
}
7474

7575
// readVersionFile gets the version file info
76-
func readVersionFile(path string) (Entries, error) {
77-
info := make(Entries)
76+
func readVersionFile(path string) (*VFile, error) {
77+
var info VFile
78+
7879
p, err := filepath.Abs(path)
7980
if err != nil {
8081
return nil, err
@@ -100,7 +101,7 @@ func readVersionFile(path string) (Entries, error) {
100101
default:
101102
return nil, fmt.Errorf("unsupported file type")
102103
}
103-
return info, nil
104+
return &info, nil
104105
}
105106

106107
// Open a version entries file.
@@ -123,7 +124,10 @@ func Open(path string, creat bool) (*VEntry, error) {
123124
defer f.Close()
124125
ve.path = p
125126
ve.lck = flock.New(p + ".lck")
126-
ve.ent = make(Entries)
127+
ve.ent = &VFile{
128+
Version: make(Entries),
129+
Prev: make(Rollback),
130+
}
127131
log.Debugf("Open(): path->%s VEntry->%+#v", path, ve)
128132
return &ve, nil
129133
}
@@ -141,13 +145,20 @@ func (v *VEntry) LPath() string {
141145
// Add will update/add an entry
142146
func (v *VEntry) Add(name string, ent *Vers) {
143147
log.Debugf("Add(): enrty->%s values->%+#v", name, ent)
144-
v.ent[name] = ent
148+
// push current values to history
149+
if ve, ok := v.ent.Version[name]; ok {
150+
v.ent.Prev[name] = *ve
151+
}
152+
v.ent.Version[name] = ent
145153
}
146154

147155
// Rm will remove an entry
148156
func (v *VEntry) Rm(name string) {
149-
if _, ok := v.ent[name]; ok {
150-
delete(v.ent, name)
157+
if _, ok := v.ent.Version[name]; ok {
158+
delete(v.ent.Version, name)
159+
}
160+
if _, ok := v.ent.Prev[name]; ok {
161+
delete(v.ent.Prev, name)
151162
}
152163
}
153164

@@ -158,19 +169,19 @@ func (v *VEntry) Dump(format string) error {
158169
case "str":
159170
fallthrough
160171
case "shell":
161-
for name, _ := range v.ent {
172+
for name, _ := range v.ent.Version {
162173
v.Print(name, format)
163174
}
164175
case "json":
165-
out, err := json.MarshalIndent(v.ent, "", " ")
176+
out, err := json.MarshalIndent(v.ent.Version, "", " ")
166177
if err != nil {
167178
return err
168179
}
169180
fmt.Println(string(out))
170181
case "yml":
171182
fallthrough
172183
case "yaml":
173-
out, err := yaml.Marshal(v.ent)
184+
out, err := yaml.Marshal(v.ent.Version)
174185
if err != nil {
175186
return err
176187
}
@@ -183,7 +194,7 @@ func (v *VEntry) Dump(format string) error {
183194

184195
// Print will dump name(d) entries
185196
func (v *VEntry) Print(name, format string) error {
186-
ve, ok := v.ent[name]
197+
ve, ok := v.ent.Version[name]
187198
if !ok {
188199
return fmt.Errorf("%s; does not exist", name)
189200
}
@@ -251,7 +262,7 @@ func (v *VEntry) Write(retry int) error {
251262
}
252263
if ok {
253264
defer v.lck.Unlock()
254-
return writeVersionFile(v.path, &v.ent)
265+
return writeVersionFile(v.path, v.ent)
255266
}
256267
time.Sleep(100 * time.Millisecond)
257268
}
@@ -271,10 +282,12 @@ func (v *VEntry) Bump(name, what string) error {
271282
if ok {
272283
defer v.lck.Unlock()
273284
v.ent, err = readVersionFile(v.path)
274-
ve, ok := v.ent[name]
285+
ve, ok := v.ent.Version[name]
275286
if !ok {
276287
return fmt.Errorf("%s; does not exist", name)
277288
}
289+
// push current values to history
290+
v.ent.Prev[name] = *ve
278291
switch what {
279292
case "major":
280293
ve.Major++
@@ -288,7 +301,36 @@ func (v *VEntry) Bump(name, what string) error {
288301
default:
289302
return errors.New("Invalid bump setting")
290303
}
291-
return writeVersionFile(v.path, &v.ent)
304+
return writeVersionFile(v.path, v.ent)
305+
}
306+
time.Sleep(100 * time.Millisecond)
307+
}
308+
log.Debugf("Bump(): did not lock file", v.Path())
309+
return errors.New("Did not obtain lock")
310+
}
311+
312+
// Undo restore previous value
313+
func (v *VEntry) Undo(name string) error {
314+
var rt int
315+
for rt < 10 {
316+
rt++
317+
ok, err := v.lck.TryLock()
318+
if err != nil {
319+
return err
320+
}
321+
if ok {
322+
defer v.lck.Unlock()
323+
v.ent, err = readVersionFile(v.path)
324+
if _, ok := v.ent.Version[name]; !ok {
325+
return fmt.Errorf("%s; does not exist", name)
326+
}
327+
328+
if ve, ok := v.ent.Prev[name]; ok {
329+
v.ent.Version[name] = &ve
330+
delete(v.ent.Prev, name)
331+
return writeVersionFile(v.path, v.ent)
332+
}
333+
return fmt.Errorf("%s; previous value does not exist", name)
292334
}
293335
time.Sleep(100 * time.Millisecond)
294336
}
@@ -308,12 +350,12 @@ func (v *VEntry) Delete(name string) error {
308350
if ok {
309351
defer v.lck.Unlock()
310352
v.ent, err = readVersionFile(v.path)
311-
_, ok := v.ent[name]
353+
_, ok := v.ent.Version[name]
312354
if !ok {
313355
return fmt.Errorf("%s; does not exist", name)
314356
}
315357
v.Rm(name)
316-
return writeVersionFile(v.path, &v.ent)
358+
return writeVersionFile(v.path, v.ent)
317359
}
318360
time.Sleep(100 * time.Millisecond)
319361
}

ventry/types.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import "github.com/gofrs/flock"
44

55
// Vers tracks single program version.
66
type Vers struct {
7+
Tag string
78
Prefix string
89
Suffix string
910
Major int
@@ -14,9 +15,19 @@ type Vers struct {
1415
// Entries one or more versions.
1516
type Entries map[string]*Vers
1617

18+
// Rollback is how we keep a history (for now a single item)
19+
type Rollback map[string]Vers
20+
21+
// VFile represents the format we write to the version file it
22+
// has the current version and a history/rollback hash and array
23+
type VFile struct {
24+
Version Entries
25+
Prev Rollback
26+
}
27+
1728
// Vers is a file locked instance of entries
1829
type VEntry struct {
1930
lck *flock.Flock
2031
path string
21-
ent Entries
32+
ent *VFile
2233
}

0 commit comments

Comments
 (0)