139 lines
3.0 KiB
Go
139 lines
3.0 KiB
Go
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)
|
|
}
|