github.com/wrgl/wrgl@v0.14.0/pkg/ref/refs.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright © 2022 Wrangle Ltd
     3  
     4  package ref
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/hex"
     9  	"fmt"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/google/uuid"
    14  	"github.com/wrgl/wrgl/pkg/objects"
    15  )
    16  
    17  const (
    18  	HeadPrefix           = "heads/"
    19  	TagPrefix            = "tags/"
    20  	RemoteRefPrefix      = "remotes/"
    21  	TransactionRefPrefix = "txs/"
    22  )
    23  
    24  func HeadRef(name string) string {
    25  	return HeadPrefix + name
    26  }
    27  
    28  func tagRef(name string) string {
    29  	return TagPrefix + name
    30  }
    31  
    32  func TransactionRef(tid, branch string) string {
    33  	return fmt.Sprintf("%s%s/%s", TransactionRefPrefix, tid, branch)
    34  }
    35  
    36  func RemoteRef(remote, name string) string {
    37  	return fmt.Sprintf("%s%s/%s", string(RemoteRefPrefix), remote, name)
    38  }
    39  
    40  func SaveFetchRef(s Store, name string, commit []byte, authorName, authorEmail, remote, message string) error {
    41  	return SaveRef(s, name, commit, authorName, authorEmail, "fetch", fmt.Sprintf("[from %s] %s", remote, message), nil)
    42  }
    43  
    44  func SaveRef(s Store, name string, commit []byte, authorName, authorEmail, action, message string, txid *uuid.UUID) error {
    45  	reflog := &Reflog{
    46  		AuthorName:  authorName,
    47  		AuthorEmail: authorEmail,
    48  		Action:      action,
    49  		Message:     message,
    50  		Time:        time.Now(),
    51  		NewOID:      commit,
    52  		Txid:        txid,
    53  	}
    54  	if b, err := s.Get(name); err == nil {
    55  		reflog.OldOID = b
    56  	}
    57  	return s.SetWithLog(name, commit, reflog)
    58  }
    59  
    60  func FirstLine(s string) string {
    61  	i := bytes.IndexByte([]byte(s), '\n')
    62  	if i == -1 {
    63  		return s
    64  	}
    65  	return s[:i]
    66  }
    67  
    68  func CommitHead(s Store, name string, sum []byte, commit *objects.Commit, txid *uuid.UUID) error {
    69  	return SaveRef(s, HeadRef(name), sum, commit.AuthorName, commit.AuthorEmail, "commit", FirstLine(commit.Message), txid)
    70  }
    71  
    72  func CommitMerge(s Store, branch string, sum []byte, commit *objects.Commit) error {
    73  	parents := []string{}
    74  	for _, parent := range commit.Parents {
    75  		parents = append(parents, hex.EncodeToString(parent)[:7])
    76  	}
    77  	return SaveRef(s, HeadRef(branch), sum, commit.AuthorName, commit.AuthorEmail, "merge", fmt.Sprintf(
    78  		"merge %s", strings.Join(parents, ", "),
    79  	), nil)
    80  }
    81  
    82  func SaveTag(s Store, name string, sum []byte) error {
    83  	return s.Set(tagRef(name), sum)
    84  }
    85  
    86  func SaveRemoteRef(s Store, remote, name string, commit []byte, authorName, authorEmail, action, message string) error {
    87  	return SaveRef(s, RemoteRef(remote, name), commit, authorName, authorEmail, action, message, nil)
    88  }
    89  
    90  func SaveTransactionRef(s Store, tid uuid.UUID, branch string, sum []byte) error {
    91  	return s.Set(TransactionRef(tid.String(), branch), sum)
    92  }
    93  
    94  func GetRef(s Store, name string) ([]byte, error) {
    95  	return s.Get(name)
    96  }
    97  
    98  func GetHead(s Store, name string) ([]byte, error) {
    99  	return s.Get(HeadRef(name))
   100  }
   101  
   102  func GetTag(s Store, name string) ([]byte, error) {
   103  	return s.Get(tagRef(name))
   104  }
   105  
   106  func GetRemoteRef(s Store, remote, name string) ([]byte, error) {
   107  	return s.Get(RemoteRef(remote, name))
   108  }
   109  
   110  func listRefs(s Store, prefix string) (map[string][]byte, error) {
   111  	result := map[string][]byte{}
   112  	m, err := s.Filter([]string{prefix}, nil)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	l := len(prefix)
   117  	for k, v := range m {
   118  		name := k[l:]
   119  		result[name] = v
   120  	}
   121  	return result, nil
   122  }
   123  
   124  func ListTransactionRefs(s Store, id uuid.UUID) (map[string][]byte, error) {
   125  	return listRefs(s, TransactionRef(id.String(), ""))
   126  }
   127  
   128  func ListHeads(s Store) (map[string][]byte, error) {
   129  	return listRefs(s, HeadPrefix)
   130  }
   131  
   132  func ListTags(s Store) (map[string][]byte, error) {
   133  	return listRefs(s, TagPrefix)
   134  }
   135  
   136  func ListRemoteRefs(s Store, remote string) (map[string][]byte, error) {
   137  	return listRefs(s, RemoteRef(remote, ""))
   138  }
   139  
   140  func ListAllRefs(s Store) (map[string][]byte, error) {
   141  	return s.Filter(nil, nil)
   142  }
   143  
   144  func ListLocalRefs(s Store, prefixes, notPrefixes []string) (map[string][]byte, error) {
   145  	notPrefixes = append(notPrefixes, RemoteRefPrefix)
   146  	m, err := s.Filter(prefixes, notPrefixes)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  	return m, nil
   151  }
   152  
   153  func DeleteRef(s Store, name string) error {
   154  	return s.Delete(name)
   155  }
   156  
   157  func DeleteHead(s Store, name string) error {
   158  	return DeleteRef(s, "heads/"+name)
   159  }
   160  
   161  func DeleteTag(s Store, name string) error {
   162  	return s.Delete(tagRef(name))
   163  }
   164  
   165  func DeleteRemoteRef(s Store, remote, name string) error {
   166  	return DeleteRef(s, fmt.Sprintf("remotes/%s/%s", remote, name))
   167  }
   168  
   169  func DeleteAllRemoteRefs(s Store, remote string) error {
   170  	keys, err := s.FilterKey([]string{RemoteRef(remote, "")}, nil)
   171  	if err != nil {
   172  		return err
   173  	}
   174  	for _, b := range keys {
   175  		err = s.Delete(b)
   176  		if err != nil {
   177  			return err
   178  		}
   179  	}
   180  	return nil
   181  }
   182  
   183  func DeleteTransactionRefs(s Store, id uuid.UUID) error {
   184  	keys, err := s.FilterKey([]string{TransactionRef(id.String(), "")}, nil)
   185  	if err != nil {
   186  		return err
   187  	}
   188  	for _, b := range keys {
   189  		err = s.Delete(b)
   190  		if err != nil {
   191  			return err
   192  		}
   193  	}
   194  	return nil
   195  }
   196  
   197  func RenameRef(s Store, oldName, newName string) (sum []byte, err error) {
   198  	sum, err = s.Get(oldName)
   199  	if err != nil {
   200  		return
   201  	}
   202  	err = s.Rename(oldName, newName)
   203  	if err != nil {
   204  		return
   205  	}
   206  	return sum, nil
   207  }
   208  
   209  func CopyRef(s Store, srcName, dstName string) (sum []byte, err error) {
   210  	sum, err = s.Get(srcName)
   211  	if err != nil {
   212  		return
   213  	}
   214  	err = s.Copy(srcName, dstName)
   215  	if err != nil {
   216  		return
   217  	}
   218  	return sum, nil
   219  }
   220  
   221  func RenameAllRemoteRefs(s Store, oldRemote, newRemote string) error {
   222  	prefix := RemoteRef(oldRemote, "")
   223  	n := len(prefix)
   224  	keys, err := s.FilterKey([]string{prefix}, nil)
   225  	if err != nil {
   226  		return err
   227  	}
   228  	for _, k := range keys {
   229  		name := string(k[n:])
   230  		err = s.Rename(RemoteRef(oldRemote, name), RemoteRef(newRemote, name))
   231  		if err != nil {
   232  			return err
   233  		}
   234  	}
   235  	return nil
   236  }