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
|
package pama
import (
"crypto/rand"
"encoding/base64"
"fmt"
mathrand "math/rand"
"slices"
"strings"
"git.sr.ht/~rjarry/aerc/lib/log"
"git.sr.ht/~rjarry/aerc/lib/pama/models"
)
func (m PatchManager) CurrentProject() (p models.Project, err error) {
store := m.store()
name, err := store.CurrentName()
if name == "" || err != nil {
log.Errorf("failed to get current name: %v", storeErr(err))
err = fmt.Errorf("no current project set. " +
"Run :patch init first")
return
}
names, err := store.Names()
if err != nil {
err = storeErr(err)
return
}
notFound := true
if slices.Contains(names, name) {
notFound = !notFound
}
if notFound {
err = fmt.Errorf("project '%s' does not exist anymore. "+
"Run :patch init or :patch switch", name)
return
}
p, err = store.Current()
if err != nil {
err = storeErr(err)
}
return
}
func (m PatchManager) CurrentPatches() ([]string, error) {
c, err := m.CurrentProject()
if err != nil {
return nil, err
}
return models.Commits(c.Commits).Tags(), nil
}
func (m PatchManager) Head(p models.Project) (string, error) {
rc, err := m.rc(p.RevctrlID, p.Root)
if err != nil {
return "", revErr(err)
}
return rc.Head()
}
func (m PatchManager) Clean(p models.Project) bool {
rc, err := m.rc(p.RevctrlID, p.Root)
if err != nil {
log.Errorf("could not get revctl: %v", revErr(err))
return false
}
return rc.Clean()
}
func (m PatchManager) ApplyCmd(p models.Project) (string, error) {
rc, err := m.rc(p.RevctrlID, p.Root)
if err != nil {
return "", revErr(err)
}
return rc.ApplyCmd(), nil
}
func generateTag(n int) (string, error) {
b := make([]byte, n)
_, err := rand.Read(b)
if err != nil {
return "", err
}
return base64.RawURLEncoding.EncodeToString(b), nil
}
func makeUnique(s string) string {
tag, err := generateTag(4)
if err != nil {
return fmt.Sprintf("%s_%d", s, mathrand.Uint32())
}
return fmt.Sprintf("%s_%s", s, tag)
}
// ApplyUpdate is called after the commits have been applied with the
// ApplyCmd(). It will determine the additional commits from the commitID (last
// HEAD position), assign the patch tag to those commits and store them in
// project p.
func (m PatchManager) ApplyUpdate(p models.Project, patch, commitID string,
kv map[string]string,
) (models.Project, error) {
rc, err := m.rc(p.RevctrlID, p.Root)
if err != nil {
return p, revErr(err)
}
commitIDs, err := rc.History(commitID)
if err != nil {
return p, revErr(err)
}
if len(commitIDs) == 0 {
return p, fmt.Errorf("no commits found for patch %s", patch)
}
if models.Commits(p.Commits).HasTag(patch) {
log.Warnf("Patch name '%s' already exists", patch)
patch = makeUnique(patch)
log.Warnf("Creating new name: '%s'", patch)
}
for _, c := range commitIDs {
nc := models.NewCommit(rc, c, patch)
for msgid, subj := range kv {
if nc.Subject == "" {
continue
}
if strings.Contains(subj, nc.Subject) {
nc.MessageId = msgid
}
}
p.Commits = append(p.Commits, nc)
}
err = m.store().StoreProject(p, true)
return p, storeErr(err)
}
|