Skip to content

Commit 663bd85

Browse files
authored
Merge pull request #126 from sean-callahan/develop
fix #123: incorrect incompatibility flags
2 parents 807950a + 7a38183 commit 663bd85

File tree

5 files changed

+131
-58
lines changed

5 files changed

+131
-58
lines changed

src/factorio_server.go

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ import (
1616
"strings"
1717
"time"
1818

19-
"github.com/majormjr/rcon"
2019
"regexp"
21-
"github.com/Masterminds/semver"
20+
21+
"github.com/majormjr/rcon"
2222
)
2323

2424
type FactorioServer struct {
@@ -28,9 +28,8 @@ type FactorioServer struct {
2828
BindIP string `json:"bindip"`
2929
Port int `json:"port"`
3030
Running bool `json:"running"`
31-
Version string `json:"fac_version"`
31+
Version Version `json:"fac_version"`
3232
BaseModVersion string `json:"base_mod_version"`
33-
SemVerVersion *semver.Version `json:"-"`
3433
StdOut io.ReadCloser `json:"-"`
3534
StdErr io.ReadCloser `json:"-"`
3635
StdIn io.WriteCloser `json:"-"`
@@ -97,7 +96,6 @@ func initFactorio() (f *FactorioServer, err error) {
9796

9897
log.Printf("Loaded Factorio settings from %s\n", settingsPath)
9998

100-
10199
//Load factorio version
102100
out, err := exec.Command(config.FactorioBinary, "--version").Output()
103101
if err != nil {
@@ -107,7 +105,11 @@ func initFactorio() (f *FactorioServer, err error) {
107105

108106
reg := regexp.MustCompile("Version.*?((\\d+\\.)?(\\d+\\.)?(\\*|\\d+)+)")
109107
found := reg.FindStringSubmatch(string(out))
110-
f.Version = found[1]
108+
err = f.Version.UnmarshalText([]byte(found[1]))
109+
if err != nil {
110+
log.Printf("could not parse version: %v", err)
111+
return
112+
}
111113

112114
//Load baseMod version
113115
baseModInfoFile := filepath.Join(config.FactorioDir, "data", "base", "info.json")
@@ -124,10 +126,6 @@ func initFactorio() (f *FactorioServer, err error) {
124126
}
125127

126128
f.BaseModVersion = modInfo.Version
127-
f.SemVerVersion, err = semver.NewVersion(modInfo.Version)
128-
if err != nil {
129-
log.Fatalf("error loading semver-factorio-version: %s", err)
130-
}
131129

132130
return
133131
}

src/handlers.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package main
33
import (
44
"encoding/json"
55
"fmt"
6-
"github.com/gorilla/mux"
76
"io"
87
"io/ioutil"
98
"log"
@@ -12,6 +11,8 @@ import (
1211
"path/filepath"
1312
"strconv"
1413
"time"
14+
15+
"github.com/gorilla/mux"
1516
)
1617

1718
type JSONResponse struct {
@@ -443,7 +444,7 @@ func FactorioVersion(w http.ResponseWriter, r *http.Request) {
443444
w.Header().Set("Content-Type", "application/json;charset=UTF-8")
444445

445446
status := map[string]string{}
446-
status["version"] = FactorioServ.Version
447+
status["version"] = FactorioServ.Version.String()
447448
status["base_mod_version"] = FactorioServ.BaseModVersion
448449

449450
resp.Data = status

src/mod_modInfo.go

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ type ModInfoList struct {
1818
Destination string `json:"-"`
1919
}
2020
type ModInfo struct {
21-
Name string `json:"name"`
22-
Version string `json:"version"`
23-
Title string `json:"title"`
24-
Author string `json:"author"`
25-
FileName string `json:"file_name"`
26-
FactorioVersion string `json:"factorio_version"`
27-
Dependencies []string `json:"dependencies"`
28-
Compatibility bool `json:"compatibility"`
21+
Name string `json:"name"`
22+
Version string `json:"version"`
23+
Title string `json:"title"`
24+
Author string `json:"author"`
25+
FileName string `json:"file_name"`
26+
FactorioVersion Version `json:"factorio_version"`
27+
Dependencies []string `json:"dependencies"`
28+
Compatibility bool `json:"compatibility"`
2929
}
3030

3131
func newModInfoList(destination string) (ModInfoList, error) {
@@ -74,33 +74,43 @@ func (modInfoList *ModInfoList) listInstalledMods() error {
7474

7575
modInfo.FileName = info.Name()
7676

77-
var baseDependency string
78-
for _, dependency := range modInfo.Dependencies {
79-
if strings.HasPrefix(dependency, "base") {
80-
splittedDep := strings.Split(dependency, "=")
77+
var base Version
78+
var op string
79+
for _, dep := range modInfo.Dependencies {
80+
dep = strings.TrimSpace(dep)
81+
if dep == "" {
82+
continue
83+
}
84+
85+
parts := strings.Split(dep, " ")
86+
if len(parts) > 3 {
87+
log.Printf("skipping dependency '%s' in '%s': invalid format\n", dep, modInfo.Name)
88+
continue
89+
}
90+
if parts[0] != "base" {
91+
continue
92+
}
93+
if len(parts) == 1 {
94+
base = modInfo.FactorioVersion
95+
op = ">="
96+
continue
97+
}
8198

82-
if len(splittedDep) == 1 {
83-
log.Printf("basemod without version specified!")
84-
break
85-
}
99+
op = parts[1]
86100

87-
baseDependency = strings.Split(dependency, "=")[1]
88-
break
101+
if err := base.UnmarshalText([]byte(parts[2])); err != nil {
102+
log.Printf("skipping dependency '%s' in '%s': %v\n", dep, modInfo.Name, err)
103+
continue
89104
}
105+
106+
break
90107
}
91-
if baseDependency != "" {
92-
modInfo.Compatibility, err = checkModCompatibility(baseDependency)
93-
if err != nil {
94-
log.Printf("error checking mod compatibility: %s", err)
95-
return err
96-
}
108+
109+
if !base.Equals(NilVersion) {
110+
modInfo.Compatibility = FactorioServ.Version.Compare(base, op)
97111
} else {
98112
log.Println("error finding basemodDependency. Using FactorioVersion...")
99-
modInfo.Compatibility, err = checkModCompatibility(modInfo.FactorioVersion + ".0")
100-
if err != nil {
101-
log.Printf("error checking Compatibility with FactorioVersion: %s", err)
102-
return err
103-
}
113+
modInfo.Compatibility = !FactorioServ.Version.Less(modInfo.FactorioVersion)
104114
}
105115

106116
modInfoList.Mods = append(modInfoList.Mods, modInfo)

src/mods.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"os"
1313
"path/filepath"
1414
"strings"
15-
"github.com/Masterminds/semver"
1615
)
1716

1817
type LoginErrorResponse struct {
@@ -345,19 +344,3 @@ func modStartUp() {
345344
}
346345
}
347346
}
348-
349-
func checkModCompatibility(modVersion string) (compatible bool, err error) {
350-
compatible = false
351-
modVersion = strings.TrimSpace(modVersion)
352-
if !strings.HasPrefix(modVersion, "~") {
353-
modVersion = "~" + modVersion
354-
}
355-
356-
constraint, err := semver.NewConstraint(modVersion)
357-
if err != nil {
358-
log.Printf("error loading constraint: %s", err)
359-
return
360-
}
361-
362-
return constraint.Check(FactorioServ.SemVerVersion), nil
363-
}

src/version.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
"strings"
7+
)
8+
9+
// NilVersion represents an empty version number
10+
var NilVersion = Version{0, 0, 0}
11+
12+
// Version represents a semantic version
13+
type Version [3]uint
14+
15+
func (v Version) String() string {
16+
return fmt.Sprintf("%d.%d.%d", v[0], v[1], v[2])
17+
}
18+
19+
// MarshalText implements encoding.TextMarshaller for Version
20+
func (v Version) MarshalText() (text []byte, err error) {
21+
return []byte(v.String()), nil
22+
}
23+
24+
// UnmarshalText implements encoding.TextUnmarshaller for Version
25+
func (v *Version) UnmarshalText(text []byte) error {
26+
parts := strings.SplitN(string(text), ".", 3)
27+
for i, part := range parts {
28+
p, err := strconv.ParseUint(part, 10, 32)
29+
if err != nil {
30+
return err
31+
}
32+
v[i] = uint(p)
33+
}
34+
return nil
35+
}
36+
37+
// Equals returns true if both version are equal
38+
func (v Version) Equals(b Version) bool {
39+
return v[0] == b[0] && v[1] == b[1] && v[2] == b[2]
40+
}
41+
42+
// Less returns true if the receiver version is less than the argument version
43+
func (v Version) Less(b Version) bool {
44+
switch {
45+
case v[0] < b[0]:
46+
return true
47+
case v[0] == b[0] && v[1] < b[1]:
48+
return true
49+
case v[0] == b[0] && v[1] == b[1] && v[2] < b[2]:
50+
return true
51+
default:
52+
return false
53+
}
54+
}
55+
56+
// Greater returns true if the receiver version is greater than the argument version
57+
func (v Version) Greater(b Version) bool { return !v.Equals(b) && !v.Less(b) }
58+
59+
func (v Version) ge(b Version) bool { return v.Equals(b) || v.Greater(b) }
60+
func (v Version) le(b Version) bool { return v.Equals(b) || v.Less(b) }
61+
62+
// Compare returns true if the comparison between the two version operands is valid.
63+
// Supported ops are: ==, !=, >, <, >=, <=
64+
func (v Version) Compare(b Version, op string) bool {
65+
switch op {
66+
case "==":
67+
return v.Equals(b)
68+
case "!=":
69+
return !v.Equals(b)
70+
case ">":
71+
return v.Greater(b)
72+
case "<":
73+
return v.Less(b)
74+
case ">=":
75+
return v.ge(b)
76+
case "<=":
77+
return v.le(b)
78+
default:
79+
panic("unsupported operator")
80+
}
81+
}

0 commit comments

Comments
 (0)