code.gitea.io/gitea@v1.19.3/modules/git/utils.go (about)

     1  // Copyright 2015 The Gogs Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package git
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"os"
    10  	"strconv"
    11  	"strings"
    12  	"sync"
    13  
    14  	"code.gitea.io/gitea/modules/util"
    15  )
    16  
    17  // ObjectCache provides thread-safe cache operations.
    18  type ObjectCache struct {
    19  	lock  sync.RWMutex
    20  	cache map[string]interface{}
    21  }
    22  
    23  func newObjectCache() *ObjectCache {
    24  	return &ObjectCache{
    25  		cache: make(map[string]interface{}, 10),
    26  	}
    27  }
    28  
    29  // Set add obj to cache
    30  func (oc *ObjectCache) Set(id string, obj interface{}) {
    31  	oc.lock.Lock()
    32  	defer oc.lock.Unlock()
    33  
    34  	oc.cache[id] = obj
    35  }
    36  
    37  // Get get cached obj by id
    38  func (oc *ObjectCache) Get(id string) (interface{}, bool) {
    39  	oc.lock.RLock()
    40  	defer oc.lock.RUnlock()
    41  
    42  	obj, has := oc.cache[id]
    43  	return obj, has
    44  }
    45  
    46  // isDir returns true if given path is a directory,
    47  // or returns false when it's a file or does not exist.
    48  func isDir(dir string) bool {
    49  	f, e := os.Stat(dir)
    50  	if e != nil {
    51  		return false
    52  	}
    53  	return f.IsDir()
    54  }
    55  
    56  // isFile returns true if given path is a file,
    57  // or returns false when it's a directory or does not exist.
    58  func isFile(filePath string) bool {
    59  	f, e := os.Stat(filePath)
    60  	if e != nil {
    61  		return false
    62  	}
    63  	return !f.IsDir()
    64  }
    65  
    66  // isExist checks whether a file or directory exists.
    67  // It returns false when the file or directory does not exist.
    68  func isExist(path string) bool {
    69  	_, err := os.Stat(path)
    70  	return err == nil || os.IsExist(err)
    71  }
    72  
    73  // ConcatenateError concatenats an error with stderr string
    74  func ConcatenateError(err error, stderr string) error {
    75  	if len(stderr) == 0 {
    76  		return err
    77  	}
    78  	return fmt.Errorf("%w - %s", err, stderr)
    79  }
    80  
    81  // RefEndName return the end name of a ref name
    82  func RefEndName(refStr string) string {
    83  	if strings.HasPrefix(refStr, BranchPrefix) {
    84  		return refStr[len(BranchPrefix):]
    85  	}
    86  
    87  	if strings.HasPrefix(refStr, TagPrefix) {
    88  		return refStr[len(TagPrefix):]
    89  	}
    90  
    91  	return refStr
    92  }
    93  
    94  // RefURL returns the absolute URL for a ref in a repository
    95  func RefURL(repoURL, ref string) string {
    96  	refName := util.PathEscapeSegments(RefEndName(ref))
    97  	switch {
    98  	case strings.HasPrefix(ref, BranchPrefix):
    99  		return repoURL + "/src/branch/" + refName
   100  	case strings.HasPrefix(ref, TagPrefix):
   101  		return repoURL + "/src/tag/" + refName
   102  	case !IsValidSHAPattern(ref):
   103  		// assume they mean a branch
   104  		return repoURL + "/src/branch/" + refName
   105  	default:
   106  		return repoURL + "/src/commit/" + refName
   107  	}
   108  }
   109  
   110  // SplitRefName splits a full refname to reftype and simple refname
   111  func SplitRefName(refStr string) (string, string) {
   112  	if strings.HasPrefix(refStr, BranchPrefix) {
   113  		return BranchPrefix, refStr[len(BranchPrefix):]
   114  	}
   115  
   116  	if strings.HasPrefix(refStr, TagPrefix) {
   117  		return TagPrefix, refStr[len(TagPrefix):]
   118  	}
   119  
   120  	return "", refStr
   121  }
   122  
   123  // ParseBool returns the boolean value represented by the string as per git's git_config_bool
   124  // true will be returned for the result if the string is empty, but valid will be false.
   125  // "true", "yes", "on" are all true, true
   126  // "false", "no", "off" are all false, true
   127  // 0 is false, true
   128  // Any other integer is true, true
   129  // Anything else will return false, false
   130  func ParseBool(value string) (result, valid bool) {
   131  	// Empty strings are true but invalid
   132  	if len(value) == 0 {
   133  		return true, false
   134  	}
   135  	// These are the git expected true and false values
   136  	if strings.EqualFold(value, "true") || strings.EqualFold(value, "yes") || strings.EqualFold(value, "on") {
   137  		return true, true
   138  	}
   139  	if strings.EqualFold(value, "false") || strings.EqualFold(value, "no") || strings.EqualFold(value, "off") {
   140  		return false, true
   141  	}
   142  	// Try a number
   143  	intValue, err := strconv.ParseInt(value, 10, 32)
   144  	if err != nil {
   145  		return false, false
   146  	}
   147  	return intValue != 0, true
   148  }
   149  
   150  // LimitedReaderCloser is a limited reader closer
   151  type LimitedReaderCloser struct {
   152  	R io.Reader
   153  	C io.Closer
   154  	N int64
   155  }
   156  
   157  // Read implements io.Reader
   158  func (l *LimitedReaderCloser) Read(p []byte) (n int, err error) {
   159  	if l.N <= 0 {
   160  		_ = l.C.Close()
   161  		return 0, io.EOF
   162  	}
   163  	if int64(len(p)) > l.N {
   164  		p = p[0:l.N]
   165  	}
   166  	n, err = l.R.Read(p)
   167  	l.N -= int64(n)
   168  	return n, err
   169  }
   170  
   171  // Close implements io.Closer
   172  func (l *LimitedReaderCloser) Close() error {
   173  	return l.C.Close()
   174  }