1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-10-30 11:46:16 +00:00
mycorrhiza/history/operations.go

161 lines
3.9 KiB
Go
Raw Normal View History

package history
2021-05-11 10:14:00 +00:00
// history/operations.go
// Things related to writing history.
import (
"fmt"
"os"
"path/filepath"
2020-09-29 18:13:24 +00:00
"sync"
"github.com/bouncepaw/mycorrhiza/user"
"github.com/bouncepaw/mycorrhiza/util"
)
2020-09-29 18:13:24 +00:00
// gitMutex is used for blocking git operations to avoid clashes.
var gitMutex = sync.Mutex{}
// OpType is the type a history operation has. Callers shall set appropriate optypes when creating history operations.
type OpType int
const (
// TypeNone represents an empty operation. Not to be used in practice.
TypeNone OpType = iota
// TypeEditText represents an edit of hypha text part.
TypeEditText
// TypeEditBinary represents an addition or replacement of hypha attachment.
TypeEditBinary
// TypeDeleteHypha represents a hypha deletion
2020-09-29 15:04:22 +00:00
TypeDeleteHypha
// TypeRenameHypha represents a hypha renaming
2020-09-29 15:04:22 +00:00
TypeRenameHypha
// TypeUnattachHypha represents a hypha attachment deletion
2021-01-19 18:08:59 +00:00
TypeUnattachHypha
)
// Op is an object representing a history operation.
type Op struct {
// All errors are appended here.
Errs []error
Type OpType
userMsg string
name string
email string
}
// Operation is a constructor of a history operation.
func Operation(opType OpType) *Op {
2020-09-29 18:13:24 +00:00
gitMutex.Lock()
hop := &Op{
Errs: []error{},
name: "anon",
email: "anon@mycorrhiza",
Type: opType,
}
return hop
}
// git operation maker helper
func (hop *Op) gitop(args ...string) *Op {
out, err := gitsh(args...)
if err != nil {
fmt.Println("out:", out.String())
hop.Errs = append(hop.Errs, err)
}
return hop
}
2021-02-26 16:43:45 +00:00
// WithErr appends the `err` to the list of errors.
func (hop *Op) WithErr(err error) *Op {
hop.Errs = append(hop.Errs, err)
return hop
}
// WithErrAbort appends the `err` to the list of errors and immediately aborts the operation.
func (hop *Op) WithErrAbort(err error) *Op {
2021-02-26 16:43:45 +00:00
return hop.WithErr(err).Abort()
}
2020-09-29 15:04:22 +00:00
// WithFilesRemoved git-rm-s all passed `paths`. Paths can be rooted or not. Paths that are empty strings are ignored.
func (hop *Op) WithFilesRemoved(paths ...string) *Op {
2020-09-29 15:04:22 +00:00
args := []string{"rm", "--quiet", "--"}
for _, path := range paths {
if path != "" {
args = append(args, path)
}
}
return hop.gitop(args...)
}
2020-10-02 15:31:59 +00:00
// WithFilesRenamed git-mv-s all passed keys of `pairs` to values of `pairs`. Paths can be rooted ot not. Empty keys are ignored.
func (hop *Op) WithFilesRenamed(pairs map[string]string) *Op {
2020-10-02 15:31:59 +00:00
for from, to := range pairs {
if from != "" {
2021-05-11 10:14:00 +00:00
if err := os.MkdirAll(filepath.Dir(to), 0777); err != nil {
hop.Errs = append(hop.Errs, err)
continue
}
if err := Rename(from, to); err != nil {
hop.Errs = append(hop.Errs, err)
}
2020-10-02 15:31:59 +00:00
}
}
return hop
}
// WithFiles stages all passed `paths`. Paths can be rooted or not.
func (hop *Op) WithFiles(paths ...string) *Op {
for i, path := range paths {
paths[i] = util.ShorterPath(path)
}
// 1 git operation is more effective than n operations.
return hop.gitop(append([]string{"add"}, paths...)...)
}
// Apply applies history operation by doing the commit.
func (hop *Op) Apply() *Op {
hop.gitop(
"commit",
"--author='"+hop.name+" <"+hop.email+">'",
"--message="+hop.userMsg,
)
2020-09-29 18:13:24 +00:00
gitMutex.Unlock()
return hop
}
2021-01-21 14:21:34 +00:00
// Abort aborts the history operation.
func (hop *Op) Abort() *Op {
2021-01-21 14:21:34 +00:00
gitMutex.Unlock()
return hop
}
// WithMsg sets what message will be used for the future commit. If user message exceeds one line, it is stripped down.
func (hop *Op) WithMsg(userMsg string) *Op {
for _, ch := range userMsg {
if ch == '\r' || ch == '\n' {
break
}
hop.userMsg += string(ch)
}
return hop
}
// WithUser sets a user for the commit.
func (hop *Op) WithUser(u *user.User) *Op {
if u.Group != "anon" {
hop.name = u.Name
hop.email = u.Name + "@mycorrhiza"
}
return hop
}
2021-02-17 18:41:35 +00:00
// HasErrors checks whether operation has errors appended.
func (hop *Op) HasErrors() bool {
2021-02-17 18:41:35 +00:00
return len(hop.Errs) > 0
}
// FirstErrorText extracts first error appended to the operation.
func (hop *Op) FirstErrorText() string {
2021-02-17 18:41:35 +00:00
return hop.Errs[0].Error()
}