code.gitea.io/gitea@v1.19.3/modules/packages/conan/reference.go (about)

     1  // Copyright 2022 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package conan
     5  
     6  import (
     7  	"fmt"
     8  	"regexp"
     9  	"strings"
    10  
    11  	"code.gitea.io/gitea/modules/log"
    12  	"code.gitea.io/gitea/modules/util"
    13  )
    14  
    15  const (
    16  	// taken from https://github.com/conan-io/conan/blob/develop/conans/model/ref.py
    17  	minChars = 2
    18  	maxChars = 51
    19  
    20  	// DefaultRevision if no revision is specified
    21  	DefaultRevision = "0"
    22  )
    23  
    24  var (
    25  	namePattern     = regexp.MustCompile(fmt.Sprintf(`^[a-zA-Z0-9_][a-zA-Z0-9_\+\.-]{%d,%d}$`, minChars-1, maxChars-1))
    26  	revisionPattern = regexp.MustCompile(fmt.Sprintf(`^[a-zA-Z0-9]{1,%d}$`, maxChars))
    27  
    28  	ErrValidation = util.NewInvalidArgumentErrorf("could not validate one or more reference fields")
    29  )
    30  
    31  // RecipeReference represents a recipe <Name>/<Version>@<User>/<Channel>#<Revision>
    32  type RecipeReference struct {
    33  	Name     string
    34  	Version  string
    35  	User     string
    36  	Channel  string
    37  	Revision string
    38  }
    39  
    40  func NewRecipeReference(name, version, user, channel, revision string) (*RecipeReference, error) {
    41  	log.Trace("Conan Recipe: %s/%s(@%s/%s(#%s))", name, version, user, channel, revision)
    42  
    43  	if user == "_" {
    44  		user = ""
    45  	}
    46  	if channel == "_" {
    47  		channel = ""
    48  	}
    49  
    50  	if (user != "" && channel == "") || (user == "" && channel != "") {
    51  		return nil, ErrValidation
    52  	}
    53  
    54  	if !namePattern.MatchString(name) {
    55  		return nil, ErrValidation
    56  	}
    57  
    58  	v := strings.TrimSpace(version)
    59  	if v == "" {
    60  		return nil, ErrValidation
    61  	}
    62  	if user != "" && !namePattern.MatchString(user) {
    63  		return nil, ErrValidation
    64  	}
    65  	if channel != "" && !namePattern.MatchString(channel) {
    66  		return nil, ErrValidation
    67  	}
    68  	if revision != "" && !revisionPattern.MatchString(revision) {
    69  		return nil, ErrValidation
    70  	}
    71  
    72  	return &RecipeReference{name, v, user, channel, revision}, nil
    73  }
    74  
    75  func (r *RecipeReference) RevisionOrDefault() string {
    76  	if r.Revision == "" {
    77  		return DefaultRevision
    78  	}
    79  	return r.Revision
    80  }
    81  
    82  func (r *RecipeReference) String() string {
    83  	rev := ""
    84  	if r.Revision != "" {
    85  		rev = "#" + r.Revision
    86  	}
    87  	if r.User == "" || r.Channel == "" {
    88  		return fmt.Sprintf("%s/%s%s", r.Name, r.Version, rev)
    89  	}
    90  	return fmt.Sprintf("%s/%s@%s/%s%s", r.Name, r.Version, r.User, r.Channel, rev)
    91  }
    92  
    93  func (r *RecipeReference) LinkName() string {
    94  	user := r.User
    95  	if user == "" {
    96  		user = "_"
    97  	}
    98  	channel := r.Channel
    99  	if channel == "" {
   100  		channel = "_"
   101  	}
   102  	return fmt.Sprintf("%s/%s/%s/%s/%s", r.Name, r.Version, user, channel, r.RevisionOrDefault())
   103  }
   104  
   105  func (r *RecipeReference) WithRevision(revision string) *RecipeReference {
   106  	return &RecipeReference{r.Name, r.Version, r.User, r.Channel, revision}
   107  }
   108  
   109  // AsKey builds the additional key for the package file
   110  func (r *RecipeReference) AsKey() string {
   111  	return fmt.Sprintf("%s|%s|%s", r.User, r.Channel, r.RevisionOrDefault())
   112  }
   113  
   114  // PackageReference represents a package of a recipe <Name>/<Version>@<User>/<Channel>#<Revision> <Reference>#<Revision>
   115  type PackageReference struct {
   116  	Recipe    *RecipeReference
   117  	Reference string
   118  	Revision  string
   119  }
   120  
   121  func NewPackageReference(recipe *RecipeReference, reference, revision string) (*PackageReference, error) {
   122  	log.Trace("Conan Package: %v %s(#%s)", recipe, reference, revision)
   123  
   124  	if recipe == nil {
   125  		return nil, ErrValidation
   126  	}
   127  	if reference == "" || !revisionPattern.MatchString(reference) {
   128  		return nil, ErrValidation
   129  	}
   130  	if revision != "" && !revisionPattern.MatchString(revision) {
   131  		return nil, ErrValidation
   132  	}
   133  
   134  	return &PackageReference{recipe, reference, revision}, nil
   135  }
   136  
   137  func (r *PackageReference) RevisionOrDefault() string {
   138  	if r.Revision == "" {
   139  		return DefaultRevision
   140  	}
   141  	return r.Revision
   142  }
   143  
   144  func (r *PackageReference) LinkName() string {
   145  	return fmt.Sprintf("%s/%s", r.Reference, r.RevisionOrDefault())
   146  }
   147  
   148  func (r *PackageReference) WithRevision(revision string) *PackageReference {
   149  	return &PackageReference{r.Recipe, r.Reference, revision}
   150  }
   151  
   152  // AsKey builds the additional key for the package file
   153  func (r *PackageReference) AsKey() string {
   154  	return fmt.Sprintf("%s|%s|%s|%s|%s", r.Recipe.User, r.Recipe.Channel, r.Recipe.RevisionOrDefault(), r.Reference, r.RevisionOrDefault())
   155  }