-
Notifications
You must be signed in to change notification settings - Fork 2
/
get-py-version.go
87 lines (76 loc) · 2.47 KB
/
get-py-version.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
package main
import (
"bytes"
"fmt"
"io"
"os"
"regexp"
)
func main() {
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, "error: need exactly one argument\n")
os.Exit(-1)
}
p, err := pyPiVersionFromNpmVersion(os.Args[1])
if err != nil {
fmt.Fprintf(os.Stderr, "error: %s\n", err)
os.Exit(-1)
}
fmt.Println(p)
}
var (
releaseVersionRegex = regexp.MustCompile(
`^v(?P<version>\d+\.\d+\.\d+)(?P<dirty>\+dirty)?$`)
rcVersionRegex = regexp.MustCompile(
`^v(?P<version>\d+\.\d+\.\d+)-rc\.(?P<rcN>\d+)(?P<dirty>\+dirty)?$`)
devVersionRegex = regexp.MustCompile(
`^v(?P<version>\d+\.\d+\.\d+)-dev\.(?P<time>\d+)\+(?P<gitInfo>g[a-z0-9]+)(?P<dirty>.dirty)?$`)
)
// pyPiVersionFromNpmVersion returns a PEP-440 compliant version for a given semver version. This method does not
// support all possible semver strings, but instead just supports versions that we generate for our node packages.
//
// NOTE: We do not include git information in the generated version (even within the local part, which PEP440 would
// allow) because we publish dev packages to PyPI, which does not allow local parts. Instead, we only add a local part
// when the build is dirty (which has the nice side effect of preventing us from publishing a build from dirty bits).
func pyPiVersionFromNpmVersion(s string) (string, error) {
var b bytes.Buffer
if releaseVersionRegex.MatchString(s) {
capMap := captureToMap(releaseVersionRegex, s)
mustFprintf(&b, "%s", capMap["version"])
if capMap["dirty"] != "" {
mustFprintf(&b, "+dirty")
}
return b.String(), nil
} else if rcVersionRegex.MatchString(s) {
capMap := captureToMap(rcVersionRegex, s)
mustFprintf(&b, "%src%s", capMap["version"], capMap["rcN"])
if capMap["dirty"] != "" {
mustFprintf(&b, "+dirty")
}
return b.String(), nil
} else if devVersionRegex.MatchString(s) {
capMap := captureToMap(devVersionRegex, s)
mustFprintf(&b, "%s.dev%s", capMap["version"], capMap["time"])
if capMap["dirty"] != "" {
mustFprintf(&b, "+dirty")
}
return b.String(), nil
}
return "", fmt.Errorf("can not parse version string %q", s)
}
func captureToMap(r *regexp.Regexp, s string) map[string]string {
matches := r.FindStringSubmatch(s)
capMap := make(map[string]string)
for i, name := range r.SubexpNames() {
if name != "" {
capMap[name] = matches[i]
}
}
return capMap
}
func mustFprintf(w io.Writer, format string, a ...interface{}) {
_, err := fmt.Fprintf(w, format, a...)
if err != nil {
panic("unexpected error: " + err.Error())
}
}