arche / internal/cli/cmd_status.go

commit 154431fd
  1package cli
  2
  3import (
  4	"fmt"
  5
  6	"arche/internal/issuedb"
  7	"arche/internal/wc"
  8
  9	"github.com/spf13/cobra"
 10)
 11
 12var statusCmd = &cobra.Command{
 13	Use:     "status",
 14	Aliases: []string{"st"},
 15	Short:   "Show working copy state, conflicts, and current change",
 16	RunE: func(cmd *cobra.Command, args []string) error {
 17		r := openRepo()
 18		defer r.Close()
 19
 20		head, err := r.Head()
 21		if err != nil {
 22			return err
 23		}
 24
 25		headCommit, commitID, err := r.HeadCommit()
 26		if err != nil {
 27			return err
 28		}
 29
 30		phase, _ := r.Store.GetPhase(commitID)
 31
 32		w := wc.New(r)
 33		changes, err := w.Status()
 34		if err != nil {
 35			return err
 36		}
 37		conflicts, _ := r.Store.ListConflicts()
 38
 39		empty := ""
 40		if len(changes) == 0 && len(conflicts) == 0 {
 41			empty = ", empty"
 42		}
 43		fmt.Printf("Working copy: %s (%s%s)\n", head, phase, empty)
 44		fmt.Printf("Commit:       %x  %s\n", commitID[:8], headCommit.Message)
 45
 46		bms, _ := r.Store.ListBookmarks()
 47		var bmNames []string
 48		for _, bm := range bms {
 49			if bm.CommitID == commitID {
 50				bmNames = append(bmNames, bm.Name)
 51			}
 52		}
 53		if len(bmNames) > 0 {
 54			fmt.Printf("Bookmarks:    %v\n", bmNames)
 55		} else if len(bms) == 0 {
 56			fmt.Println("No bookmark. Run arche snap to record your first commit.")
 57		} else {
 58			fmt.Println("No bookmark points here. Create one with: arche bookmark set <name>")
 59		}
 60		fmt.Println()
 61
 62		conflictSet := make(map[string]bool, len(conflicts))
 63		for _, p := range conflicts {
 64			conflictSet[p] = true
 65		}
 66
 67		if len(changes) == 0 && len(conflicts) == 0 {
 68			fmt.Println("Nothing changed (working copy matches commit).")
 69			return nil
 70		}
 71
 72		for _, f := range changes {
 73			var label string
 74			if conflictSet[f.Path] {
 75				label = "conflict"
 76			} else {
 77				switch f.Status {
 78				case 'M':
 79					label = "modified"
 80				case 'A':
 81					label = "added   "
 82				case 'D':
 83					label = "deleted "
 84				default:
 85					label = "unknown "
 86				}
 87			}
 88			fmt.Printf("  %s  %s\n", label, f.Path)
 89		}
 90
 91		for _, p := range conflicts {
 92			if !func() bool {
 93				for _, f := range changes {
 94					if f.Path == p {
 95						return true
 96					}
 97				}
 98				return false
 99			}() {
100				fmt.Printf("  conflict  %s\n", p)
101			}
102		}
103		if len(conflicts) > 0 {
104			fmt.Printf("\n%d unresolved conflict(s). Run 'arche resolve <path>' after editing.\n", len(conflicts))
105		}
106
107		idb, err := issuedb.Open(r.ArcheDir())
108		if err == nil {
109			defer idb.Close()
110			stubs, err := idb.Issues.ListIssues()
111			if err == nil {
112				var bodyConflicts int
113				for _, st := range stubs {
114					issue, err := idb.Issues.GetIssue(st.ID)
115					if err == nil && issue.BodyConflict != nil {
116						if bodyConflicts == 0 {
117							fmt.Println()
118						}
119						fmt.Printf("  issue conflict  %s  %s\n", st.ID[:8], st.Title)
120						bodyConflicts++
121					}
122				}
123				if bodyConflicts > 0 {
124					fmt.Printf("%d issue body conflict(s). Resolve via 'arche ui'.\n", bodyConflicts)
125				}
126			}
127		}
128
129		return nil
130	},
131}