1
0
mirror of https://github.com/taigrr/wtf synced 2025-01-18 04:03:14 -08:00

add mercurial module

This commit is contained in:
Mathias Weber 2018-10-11 00:01:48 +02:00
parent 99379e6856
commit 2d173ccdc4
4 changed files with 378 additions and 0 deletions

View File

@ -35,6 +35,7 @@ import (
"github.com/senorprogrammer/wtf/jenkins"
"github.com/senorprogrammer/wtf/jira"
"github.com/senorprogrammer/wtf/logger"
"github.com/senorprogrammer/wtf/mercurial"
"github.com/senorprogrammer/wtf/newrelic"
"github.com/senorprogrammer/wtf/opsgenie"
"github.com/senorprogrammer/wtf/power"
@ -206,6 +207,8 @@ func addWidget(app *tview.Application, pages *tview.Pages, widgetName string) {
widgets = append(widgets, jira.NewWidget(app, pages))
case "logger":
widgets = append(widgets, logger.NewWidget(app))
case "mercurial":
widgets = append(widgets, mercurial.NewWidget(app, pages))
case "newrelic":
widgets = append(widgets, newrelic.NewWidget(app))
case "opsgenie":

83
mercurial/display.go Normal file
View File

@ -0,0 +1,83 @@
package mercurial
import (
"fmt"
"strings"
"unicode/utf8"
"github.com/senorprogrammer/wtf/wtf"
)
func (widget *Widget) display() {
repoData := widget.currentData()
if repoData == nil {
widget.View.SetText(" Mercurial repo data is unavailable ")
return
}
title := fmt.Sprintf("%s - [green]%s[white]", widget.Name, repoData.Repository)
widget.View.SetTitle(widget.ContextualTitle(title))
str := wtf.SigilStr(len(widget.Data), widget.Idx, widget.View) + "\n"
str = str + " [red]Branch:Bookmark[white]\n"
str = str + fmt.Sprintf(" %s:%s\n", repoData.Branch, repoData.Bookmark)
str = str + "\n"
str = str + widget.formatChanges(repoData.ChangedFiles)
str = str + "\n"
str = str + widget.formatCommits(repoData.Commits)
widget.View.SetText(str)
}
func (widget *Widget) formatChanges(data []string) string {
str := ""
str = str + " [red]Changed Files[white]\n"
if len(data) == 1 {
str = str + " [grey]none[white]\n"
} else {
for _, line := range data {
str = str + widget.formatChange(line)
}
}
return str
}
func (widget *Widget) formatChange(line string) string {
if len(line) == 0 {
return ""
}
line = strings.TrimSpace(line)
firstChar, _ := utf8.DecodeRuneInString(line)
// Revisit this and kill the ugly duplication
switch firstChar {
case 'A':
line = strings.Replace(line, "A", "[green]A[white]", 1)
case 'D':
line = strings.Replace(line, "D", "[red]D[white]", 1)
case 'M':
line = strings.Replace(line, "M", "[yellow]M[white]", 1)
case 'R':
line = strings.Replace(line, "R", "[purple]R[white]", 1)
}
return fmt.Sprintf(" %s\n", strings.Replace(line, "\"", "", -1))
}
func (widget *Widget) formatCommits(data []string) string {
str := ""
str = str + " [red]Recent Commits[white]\n"
for _, line := range data {
str = str + widget.formatCommit(line)
}
return str
}
func (widget *Widget) formatCommit(line string) string {
return fmt.Sprintf(" %s\n", strings.Replace(line, "\"", "", -1))
}

96
mercurial/hg_repo.go Normal file
View File

@ -0,0 +1,96 @@
package mercurial
import (
"fmt"
"io/ioutil"
"os/exec"
"path"
"strings"
"github.com/senorprogrammer/wtf/wtf"
)
type MercurialRepo struct {
Branch string
Bookmark string
ChangedFiles []string
Commits []string
Repository string
Path string
}
func NewMercurialRepo(repoPath string) *MercurialRepo {
repo := MercurialRepo{Path: repoPath}
repo.Branch = strings.TrimSpace(repo.branch())
repo.Bookmark = strings.TrimSpace(repo.bookmark())
repo.ChangedFiles = repo.changedFiles()
repo.Commits = repo.commits()
repo.Repository = strings.TrimSpace(repo.Path)
return &repo
}
/* -------------------- Unexported Functions -------------------- */
func (repo *MercurialRepo) branch() string {
arg := []string{"branch", repo.repoPath()}
cmd := exec.Command("hg", arg...)
str := wtf.ExecuteCommand(cmd)
return str
}
func (repo *MercurialRepo) bookmark() string {
bookmark, err := ioutil.ReadFile(path.Join(repo.Path, ".hg", "bookmarks.current"))
if err != nil {
return ""
}
return string(bookmark)
}
func (repo *MercurialRepo) changedFiles() []string {
arg := []string{"status", repo.repoPath()}
cmd := exec.Command("hg", arg...)
str := wtf.ExecuteCommand(cmd)
data := strings.Split(str, "\n")
return data
}
func (repo *MercurialRepo) commits() []string {
numStr := fmt.Sprintf("-l %d", wtf.Config.UInt("wtf.mods.mercurial.commitCount", 10))
commitFormat := wtf.Config.UString("wtf.mods.mercurial.commitFormat", "[forestgreen]{rev}:{phase} [white]{desc|firstline|strip} [grey]{author|person} {date|age}[white]")
commitStr := fmt.Sprintf("--template=\"%s\n\"", commitFormat)
arg := []string{"log", repo.repoPath(), numStr, commitStr}
cmd := exec.Command("hg", arg...)
str := wtf.ExecuteCommand(cmd)
data := strings.Split(str, "\n")
return data
}
func (repo *MercurialRepo) pull() string {
arg := []string{"pull", repo.repoPath()}
cmd := exec.Command("hg", arg...)
str := wtf.ExecuteCommand(cmd)
return str
}
func (repo *MercurialRepo) checkout(branch string) string {
arg := []string{"checkout", repo.repoPath(), branch}
cmd := exec.Command("hg", arg...)
str := wtf.ExecuteCommand(cmd)
return str
}
func (repo *MercurialRepo) repoPath() string {
return fmt.Sprintf("--repository=%s", repo.Path)
}

196
mercurial/widget.go Normal file
View File

@ -0,0 +1,196 @@
package mercurial
import (
"github.com/gdamore/tcell"
"github.com/rivo/tview"
"github.com/senorprogrammer/wtf/wtf"
)
const HelpText = `
Keyboard commands for Mercurial:
/: Show/hide this help window
c: Checkout to branch
h: Previous mercurial repository
l: Next mercurial repository
p: Pull current mercurial repository
arrow left: Previous mercurial repository
arrow right: Next mercurial repository
`
const offscreen = -1000
const modalWidth = 80
const modalHeight = 7
type Widget struct {
wtf.HelpfulWidget
wtf.MultiSourceWidget
wtf.TextWidget
app *tview.Application
Data []*MercurialRepo
pages *tview.Pages
}
func NewWidget(app *tview.Application, pages *tview.Pages) *Widget {
widget := Widget{
HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
MultiSourceWidget: wtf.NewMultiSourceWidget("mercurial", "repository", "repositories"),
TextWidget: wtf.NewTextWidget(app, "Mercurial", "mercurial", true),
app: app,
pages: pages,
}
widget.LoadSources()
widget.SetDisplayFunction(widget.display)
widget.HelpfulWidget.SetView(widget.View)
widget.View.SetInputCapture(widget.keyboardIntercept)
return &widget
}
/* -------------------- Exported Functions -------------------- */
func (widget *Widget) Checkout() {
form := widget.modalForm("Branch to checkout:", "")
checkoutFctn := func() {
text := form.GetFormItem(0).(*tview.InputField).GetText()
repoToCheckout := widget.Data[widget.Idx]
repoToCheckout.checkout(text)
widget.pages.RemovePage("modal")
widget.app.SetFocus(widget.View)
widget.display()
widget.Refresh()
}
widget.addButtons(form, checkoutFctn)
widget.modalFocus(form)
}
func (widget *Widget) Pull() {
repoToPull := widget.Data[widget.Idx]
repoToPull.pull()
widget.Refresh()
}
func (widget *Widget) Refresh() {
repoPaths := wtf.ToStrs(wtf.Config.UList("wtf.mods.mercurial.repositories"))
widget.UpdateRefreshedAt()
widget.Data = widget.mercurialRepos(repoPaths)
widget.display()
}
/* -------------------- Unexported Functions -------------------- */
func (widget *Widget) addCheckoutButton(form *tview.Form, fctn func()) {
form.AddButton("Checkout", fctn)
}
func (widget *Widget) addButtons(form *tview.Form, checkoutFctn func()) {
widget.addCheckoutButton(form, checkoutFctn)
widget.addCancelButton(form)
}
func (widget *Widget) addCancelButton(form *tview.Form) {
cancelFn := func() {
widget.pages.RemovePage("modal")
widget.app.SetFocus(widget.View)
widget.display()
}
form.AddButton("Cancel", cancelFn)
form.SetCancelFunc(cancelFn)
}
func (widget *Widget) modalFocus(form *tview.Form) {
frame := widget.modalFrame(form)
widget.pages.AddPage("modal", frame, false, true)
widget.app.SetFocus(frame)
}
func (widget *Widget) modalForm(lbl, text string) *tview.Form {
form := tview.NewForm().
SetButtonsAlign(tview.AlignCenter).
SetButtonTextColor(tview.Styles.PrimaryTextColor)
form.AddInputField(lbl, text, 60, nil, nil)
return form
}
func (widget *Widget) modalFrame(form *tview.Form) *tview.Frame {
frame := tview.NewFrame(form).SetBorders(0, 0, 0, 0, 0, 0)
frame.SetRect(offscreen, offscreen, modalWidth, modalHeight)
frame.SetBorder(true)
frame.SetBorders(1, 1, 0, 0, 1, 1)
drawFunc := func(screen tcell.Screen, x, y, width, height int) (int, int, int, int) {
w, h := screen.Size()
frame.SetRect((w/2)-(width/2), (h/2)-(height/2), width, height)
return x, y, width, height
}
frame.SetDrawFunc(drawFunc)
return frame
}
func (widget *Widget) currentData() *MercurialRepo{
if len(widget.Data) == 0 {
return nil
}
if widget.Idx < 0 || widget.Idx >= len(widget.Data) {
return nil
}
return widget.Data[widget.Idx]
}
func (widget *Widget) mercurialRepos(repoPaths []string) []*MercurialRepo{
repos := []*MercurialRepo{}
for _, repoPath := range repoPaths {
repo := NewMercurialRepo(repoPath)
repos = append(repos, repo)
}
return repos
}
func (widget *Widget) keyboardIntercept(event *tcell.EventKey) *tcell.EventKey {
switch string(event.Rune()) {
case "/":
widget.ShowHelp()
return nil
case "h":
widget.Prev()
return nil
case "l":
widget.Next()
return nil
case "p":
widget.Pull()
return nil
case "c":
widget.Checkout()
return nil
}
switch event.Key() {
case tcell.KeyLeft:
widget.Prev()
return nil
case tcell.KeyRight:
widget.Next()
return nil
default:
return event
}
}