package pama
import (
"crypto/rand"
"encoding/base64"
"fmt"
mathrand "math/rand"
"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
for _, s := range names {
if s == name {
notFound = !notFound
break
}
}
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)
}