-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.go
140 lines (116 loc) · 3.21 KB
/
parser.go
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
package file
import (
"bytes"
"errors"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"github.com/UiP9AV6Y/buildinfo"
)
const (
Filename = "VERSION"
AltFilename = "VERSION.txt"
)
const (
// we assume the information parts are separated by this
versionConcat = "-"
)
var (
// Error when trying to parse a directory that does not contain a version file
ErrNoFile = fs.ErrNotExist
// ErrMalformedVersion is the error used when parsing invalid version information.
ErrMalformedVersion = errors.New("malformed version information")
// ErrMalformedRevision is the error used when parsing invalid revision information.
ErrMalformedRevision = errors.New("malformed revision information")
// ErrMalformedBranch is the error used when parsing invalid branch information.
ErrMalformedBranch = errors.New("malformed branch information")
)
// parser.VersionParser implementation reading information from a file
type File struct {
file string
}
// TryParse attempts to parse the version information from various
// files in the given directory. If no files known to contain version
// information exist, ErrNoRepository is returned. All other errors
// are a result of file access problems or data corruption issues.
func TryParse(path string) (*File, error) {
var file string
file = filepath.Join(path, Filename)
if _, err := os.Stat(file); err == nil {
return New(file), nil
} else if !errors.Is(err, os.ErrNotExist) {
return nil, err
}
file = filepath.Join(path, AltFilename)
if _, err := os.Stat(file); err == nil {
return New(file), nil
} else if !errors.Is(err, os.ErrNotExist) {
return nil, err
}
return nil, ErrNoFile
}
// New creates a new parser.Parser instance using the provided
// file as version information source.
func New(file string) *File {
result := &File{
file: file,
}
return result
}
// String implements the fmt.Stringer interface
func (f *File) String() string {
return fmt.Sprintf("(file=%s)", f.file)
}
// Equal compares the fields of this instance to the given one
func (f *File) Equal(o *File) bool {
if o == nil {
return f == nil
}
return o.file == f.file
}
// ParseVersionInfo implements the parser.VersionParser interface
func (f *File) ParseVersionInfo() (*buildinfo.VersionInfo, error) {
h, err := os.Open(f.file)
if err != nil {
return nil, err
}
defer h.Close()
b, err := io.ReadAll(h)
if err != nil {
return nil, err
}
return ParseVersionInfo(bytes.TrimSpace(b))
}
// ParseVersionInfo extract version information from the
// provided input. it generally can been seen as the inverse
// of VersionInfo.VersionRevision()
func ParseVersionInfo(info []byte) (*buildinfo.VersionInfo, error) {
result := buildinfo.NewVersionInfo()
parts := bytes.Split(info, []byte(versionConcat))
if len(parts) > 0 {
if len(parts[0]) > 0 {
result.Version = string(parts[0])
} else {
return nil, ErrMalformedVersion
}
} else {
return nil, ErrMalformedVersion
}
if len(parts) > 1 {
if len(parts[1]) > 0 {
result.Revision = string(parts[1])
} else {
return nil, ErrMalformedRevision
}
} // else optional
if len(parts) > 2 {
if len(parts[2]) > 0 {
result.Branch = string(parts[2])
} else {
return nil, ErrMalformedBranch
}
} // else optional
return result, nil
}