aboutsummaryrefslogtreecommitdiff
path: root/snap/parsing.go
blob: 0d1f09fe80a30d4c1a9105cbb3a4308eee74782b (plain)
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
package snap

import (
	"strings"
	"log"
	"os"
	"strconv"
)

var die = log.New(os.Stderr, "", 0)

func isEscaped(str string) bool {
	n := len(str)
	return n > 1 && str[0] == '"' && str[n - 1] == '"'; 
}

func parseEscaped(snapish string) *Relative {
	if isEscaped(snapish) {
		snapshot := strings.Trim(snapish, `"`);

		return &Relative {
			snapshot: snapshot,
		}
	}

	return nil
}

func parseRelativeSyntax(snapish, directionToken string) *Relative {
	parts := strings.Split(snapish, directionToken)
	n_parts := len(parts)

	if n_parts == 1 {
		return nil;
	}
	
	// Test if the last the last token is a numeric offset
	if offset, err := strconv.Atoi(parts[n_parts - 1]); 
		err == nil {
		
		// Two tokens (e.g. ++ or --) indicates increment syntax
		if n_parts > 2 && parts[n_parts - 2] == "" {
			die.Fatal("A snapshot reference cannot be a mix of increment syntax (e.g. my_snap++) and literal syntax (e.g. my_snap+4).")
		}

		snapshot := strings.TrimRight(snapish, directionToken + "0123456789")
		
		return &Relative {
			offset: offset,
			snapshot: snapshot,
		}
	}

	// Parse the increment / decrement syntax
	// E.g. snapshot+++ or snapshot---
	offset := 0;
	for i := n_parts - 1; i >= 1 && parts[i] == ""; i-- {
		offset += 1
	}
  
	return &Relative {
		offset: offset,
		snapshot: snapish[:len(snapish) - offset],
	}
}

func toRelative(snapish string) * Relative {
	if ref := parseEscaped(snapish); ref != nil {
		return ref;
	}

	if ref := parseRelativeSyntax(snapish, "+"); ref != nil {
		return ref;
	}

	if ref := parseRelativeSyntax(snapish, "-"); ref != nil {
		ref.offset = -ref.offset;
		return ref;
	}

	return &Relative{
		snapshot: snapish,
	};
}

func ToRelative(snapish string) * Relative {
	rel := toRelative(snapish)

	if rel.snapshot == "" {
		die.Fatal("Please provide a snapshot. You can use @ for the current filesystem and $ for the last snapshot.")
	}

	return rel
}

func ParseDiff(snapishdiff string) (fromRel, toRel *Relative) {
	snapishes := strings.Split(snapishdiff, "..")

	if len(snapishes) > 2 {
		die.Fatal("Cannot diff more than two snapshots");
	}

	fromRel = ToRelative(snapishes[0])
	toRel = &Relative{snapshot: "@"}
	if len(snapishes) == 2 {
		toRel = ToRelative(snapishes[1])
	}

	return
}