z_mirror/fmm

git clone https://git.raiguard.me/z_mirror/fmm

Caleb HeuerSupport recommended dependencies76c75f2

trunk
2.9 KiB133 linesraw
1package fmm
2
3import (
4	"encoding/json"
5	"fmt"
6	"strings"
7)
8
9type Dependency struct {
10	Name    string
11	Version *Version
12	Kind    DependencyKind
13	Req     VersionCmpRes
14}
15
16type DependencyKind uint8
17
18const (
19	DependencyRequired DependencyKind = iota
20	DependencyOptional
21	DependencyHiddenOptional
22	DependencyIncompatible
23	DependencyNoLoadOrder
24	DependencyRecommended
25)
26
27var dependencyKindString = map[DependencyKind]string{
28	DependencyOptional:       "? ",
29	DependencyHiddenOptional: "(?) ",
30	DependencyIncompatible:   "! ",
31	DependencyNoLoadOrder:    "~ ",
32	DependencyRecommended:    "+ ",
33}
34
35func NewDependency(input string) (*Dependency, error) {
36	input = strings.TrimSpace(input)
37
38	kind := DependencyRequired
39	if strings.HasPrefix(input, "!") {
40		kind = DependencyIncompatible
41		input = strings.TrimPrefix(input, "!")
42	} else if strings.HasPrefix(input, "?") {
43		kind = DependencyOptional
44		input = strings.TrimPrefix(input, "?")
45	} else if strings.HasPrefix(input, "(?)") {
46		kind = DependencyHiddenOptional
47		input = strings.TrimPrefix(input, "(?)")
48	} else if strings.HasPrefix(input, "~") {
49		kind = DependencyNoLoadOrder
50		input = strings.TrimPrefix(input, "~")
51	} else if strings.HasPrefix(input, "+") {
52		kind = DependencyRecommended
53		input = strings.TrimPrefix(input, "+")
54	}
55
56	// Iterate in reverse and find the first non-digit and non-dot
57	var ver *Version
58	for i := len(input) - 1; i >= 0; i-- {
59		if i > 0 && !(input[i] == '.' || (input[i] >= '0' && input[i] <= '9')) {
60			parsed, err := NewVersion(input[i+1:])
61			if err == nil {
62				ver = parsed
63				input = strings.TrimSpace(input[:i+1])
64			}
65			break
66		}
67	}
68
69	req := VersionAny
70	if strings.HasSuffix(input, "<=") {
71		req = VersionLtEq
72		input = strings.TrimSuffix(input, "<=")
73	} else if strings.Contains(input, "<") {
74		req = VersionLt
75		input = strings.TrimSuffix(input, "<")
76	} else if strings.Contains(input, ">=") {
77		req = VersionGtEq
78		input = strings.TrimSuffix(input, ">=")
79	} else if strings.Contains(input, ">") {
80		req = VersionGt
81		input = strings.TrimSuffix(input, ">")
82	} else if strings.Contains(input, "=") {
83		req = VersionEq
84		input = strings.TrimSuffix(input, "=")
85	}
86
87	name := strings.TrimSpace(input)
88
89	return &Dependency{name, ver, kind, req}, nil
90}
91
92func (d *Dependency) Test(ver *Version) bool {
93	if ver == nil {
94		return true
95	}
96
97	if d.Kind == DependencyIncompatible {
98		return false
99	}
100
101	if d.Req == VersionAny {
102		return true
103	}
104
105	return d.Req&ver.Cmp(d.Version) > 0
106}
107
108func (d *Dependency) ToString() string {
109	versionStr := ""
110	if d.Version != nil {
111		versionStr = d.Version.ToString(false)
112	}
113	return fmt.Sprintf("%s%s %s %s", dependencyKindString[d.Kind], d.Name, versionCmpResString[d.Req], versionStr)
114}
115
116func (d *Dependency) UnmarshalJSON(data []byte) error {
117	var s string
118	if err := json.Unmarshal(data, &s); err != nil {
119		return err
120	}
121
122	dep, err := NewDependency(s)
123	if err != nil {
124		return err
125	}
126
127	d.Name = dep.Name
128	d.Version = dep.Version
129	d.Kind = dep.Kind
130	d.Req = dep.Req
131
132	return nil
133}