-
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
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package conan
import (
"fmt"
"regexp"
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
)
const (
// taken from https://github.com/conan-io/conan/blob/develop/conans/model/ref.py
minChars = 2
maxChars = 51
// DefaultRevision if no revision is specified
DefaultRevision = "0"
)
var (
namePattern = regexp.MustCompile(fmt.Sprintf(`^[a-zA-Z0-9_][a-zA-Z0-9_\+\.-]{%d,%d}$`, minChars-1, maxChars-1))
revisionPattern = regexp.MustCompile(fmt.Sprintf(`^[a-zA-Z0-9]{1,%d}$`, maxChars))
ErrValidation = util.NewInvalidArgumentErrorf("could not validate one or more reference fields")
)
// RecipeReference represents a recipe <Name>/<Version>@<User>/<Channel>#<Revision>
type RecipeReference struct {
Name string
Version string
User string
Channel string
Revision string
}
func NewRecipeReference(name, version, user, channel, revision string) (*RecipeReference, error) {
log.Trace("Conan Recipe: %s/%s(@%s/%s(#%s))", name, version, user, channel, revision)
if user == "_" {
user = ""
}
if channel == "_" {
channel = ""
}
if (user != "" && channel == "") || (user == "" && channel != "") {
return nil, ErrValidation
}
if !namePattern.MatchString(name) {
return nil, ErrValidation
}
v := strings.TrimSpace(version)
if v == "" {
return nil, ErrValidation
}
if user != "" && !namePattern.MatchString(user) {
return nil, ErrValidation
}
if channel != "" && !namePattern.MatchString(channel) {
return nil, ErrValidation
}
if revision != "" && !revisionPattern.MatchString(revision) {
return nil, ErrValidation
}
return &RecipeReference{name, v, user, channel, revision}, nil
}
func (r *RecipeReference) RevisionOrDefault() string {
if r.Revision == "" {
return DefaultRevision
}
return r.Revision
}
func (r *RecipeReference) String() string {
rev := ""
if r.Revision != "" {
rev = "#" + r.Revision
}
if r.User == "" || r.Channel == "" {
return fmt.Sprintf("%s/%s%s", r.Name, r.Version, rev)
}
return fmt.Sprintf("%s/%s@%s/%s%s", r.Name, r.Version, r.User, r.Channel, rev)
}
func (r *RecipeReference) LinkName() string {
user := r.User
if user == "" {
user = "_"
}
channel := r.Channel
if channel == "" {
channel = "_"
}
return fmt.Sprintf("%s/%s/%s/%s/%s", r.Name, r.Version, user, channel, r.RevisionOrDefault())
}
func (r *RecipeReference) WithRevision(revision string) *RecipeReference {
return &RecipeReference{r.Name, r.Version, r.User, r.Channel, revision}
}
// AsKey builds the additional key for the package file
func (r *RecipeReference) AsKey() string {
return fmt.Sprintf("%s|%s|%s", r.User, r.Channel, r.RevisionOrDefault())
}
// PackageReference represents a package of a recipe <Name>/<Version>@<User>/<Channel>#<Revision> <Reference>#<Revision>
type PackageReference struct {
Recipe *RecipeReference
Reference string
Revision string
}
func NewPackageReference(recipe *RecipeReference, reference, revision string) (*PackageReference, error) {
log.Trace("Conan Package: %v %s(#%s)", recipe, reference, revision)
if recipe == nil {
return nil, ErrValidation
}
if reference == "" || !revisionPattern.MatchString(reference) {
return nil, ErrValidation
}
if revision != "" && !revisionPattern.MatchString(revision) {
return nil, ErrValidation
}
return &PackageReference{recipe, reference, revision}, nil
}
func (r *PackageReference) RevisionOrDefault() string {
if r.Revision == "" {
return DefaultRevision
}
return r.Revision
}
func (r *PackageReference) LinkName() string {
return fmt.Sprintf("%s/%s", r.Reference, r.RevisionOrDefault())
}
func (r *PackageReference) WithRevision(revision string) *PackageReference {
return &PackageReference{r.Recipe, r.Reference, revision}
}
// AsKey builds the additional key for the package file
func (r *PackageReference) AsKey() string {
return fmt.Sprintf("%s|%s|%s|%s|%s", r.Recipe.User, r.Recipe.Channel, r.Recipe.RevisionOrDefault(), r.Reference, r.RevisionOrDefault())
}