-
Notifications
You must be signed in to change notification settings - Fork 0
/
status.py
executable file
·126 lines (101 loc) · 3.36 KB
/
status.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import os
import sys
import shell
import utils
def _call_git_status():
stdout, *_ = shell.run(["git", "status", "--porcelain", "-b"] + sys.argv[1:])
lines = stdout.split("\n")[:-1]
branch = lines[0][3:] # starts with "## ".
return branch, [(p[:2], p[3:]) for p in lines[1:]]
def _separate_paths(paths):
index, tree, conflicts, untracked = [], [], [], []
for t in paths:
status, path = t
path = utils.relpath_from_root(path)
if status in ("??", "!!"):
untracked.append((status, path))
continue
if "U" in status or status in ("DD", "AA"):
conflicts.append((status, path))
continue
matched = False
if status[0] != " ":
index.append((status, path))
matched = True
if status[1] != " ":
tree.append((status, path))
matched = True
if not matched:
raise ValueError(f"Unknown status {status}.")
return index, tree, conflicts, untracked
def _print_path(i, status, path):
if status == "A":
# added
shell.yellow(f"\t[{i}] {status} {path}")
elif status == "M":
# modified
shell.green(f"\t[{i}] {status} {path}")
elif status in ("DD", "AA") or "U" in status:
# Conflict
shell.red(f"\t[{i}] {status} {path}")
elif status == "D":
# deleted
shell.red(f"\t[{i}] {status} {path}")
elif status in ("R", "C"):
# renamed, copied
shell.blue(f"\t[{i}] {status} {path}")
elif status in ("??", "!!"):
# untracked
shell.pink(f"\t[{i}] {status} {path}")
else:
raise ValueError(f"Unknown status '{status}'.")
def _write_cache(cache, status, path):
if status in ("R", "C"):
_, path = path.split(" -> ")
cache.write(f"{path}\n")
_MERGE_LEGEND = """
\tDD unmerged, both deleted
\tAU unmerged, added by us
\tUD unmerged, deleted by them
\tUA unmerged, added by them
\tDU unmerged, deleted by us
\tAA unmerged, both added
\tUU unmerged, both modified
"""
def _print_and_cache_status(paths, i, cache):
for status, path in paths:
_print_path(i, status, path)
_write_cache(cache, status, path)
i += 1
return i
def _print_and_cache_statuses(index, tree, conflicts, untracked):
i = 1
if not index and not tree and not conflicts and not untracked:
print("\nClean status.")
return
with open(utils.CACHE_PATH, "w") as cache:
cache.write("## status\n")
if index:
print("\nChanges to be committed:")
index = [(s[0], p) for s, p in index]
i = _print_and_cache_status(index, i, cache)
if tree:
print("\nWorking tree:")
tree = [(s[1], p) for s, p in tree]
i = _print_and_cache_status(tree, i, cache)
if untracked:
print("\nUntracked:")
i = _print_and_cache_status(untracked, i, cache)
if conflicts:
print("\nConflicts:")
i = _print_and_cache_status(conflicts, i, cache)
print(_MERGE_LEGEND)
def git_status():
os.makedirs(os.path.dirname( utils.CACHE_PATH), exist_ok=True)
branch, paths = _call_git_status()
separated = _separate_paths(paths)
print(f"On branch {branch}")
_print_and_cache_statuses(*separated)
print()
if __name__ == "__main__":
git_status()