-
Notifications
You must be signed in to change notification settings - Fork 21
/
ClassStatus.cs
191 lines (172 loc) · 6.2 KB
/
ClassStatus.cs
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace GitForce
{
/// <summary>
/// Class containing status of the files in a git repository.
/// </summary>
public class ClassStatus
{
/// <summary>
/// Reference to class repo that this Status class wraps
/// </summary>
public ClassRepo Repo;
/// <summary>
/// Lookup dictionary to get the status code string (length of 2) from a file path relative to the root.
/// </summary>
private readonly Dictionary<string, string> XY = new Dictionary<string, string>();
/// <summary>
/// Supplemental file name addressed by the primary file name, both relative to the root.
/// This is used to store the original file name of a renamed and copied files (codes 'R' and 'C')
/// </summary>
private readonly Dictionary<string, string> AltFile = new Dictionary<string, string>();
/// <summary>
/// Helper accessor to get the path to the MERGE_MSG file
/// </summary>
public string pathToMergeMsg {
get { return Repo.Path + Path.DirectorySeparatorChar + ".git" + Path.DirectorySeparatorChar + "MERGE_MSG"; } }
/// <summary>
/// Class constructor
/// </summary>
public ClassStatus(ClassRepo repo)
{
Repo = repo;
Status();
}
/// <summary>
/// Reload status fields in the context of a status class
/// </summary>
private void Status()
{
XY.Clear();
AltFile.Clear();
ExecResult result = Repo.Run("status --porcelain -uall -z");
if (!result.Success()) return;
string[] response = result.stdout
.Replace('/', Path.DirectorySeparatorChar) // Correct the path slash on Windows
.Split(("\0")
.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < response.Length; i++)
{
string s = response[i].Substring(3);
string code = response[i].Substring(0, 2);
XY[s] = code;
if ("RC".Contains(response[i][0]))
{
i++;
AltFile[s] = response[i];
}
}
}
/// <summary>
/// Returns a list of files stored in a class
/// </summary>
public List<string> GetFiles()
{
return XY.Keys.ToList();
}
/// <summary>
/// Return true if a given file is part of the git file status database
/// </summary>
public bool IsMarked(string path)
{
return XY.ContainsKey(path);
}
/// <summary>
/// Return true if the repo contains files that are not yet merged
/// </summary>
public bool IsUnmerged()
{
if (XY.Values.Any(status => status[0]=='U' || status[1]=='U'))
return true;
return false;
}
/// <summary>
/// Return true if the repo is in the merge state
/// </summary>
public bool IsMergeState()
{
string checkFile = Repo.Path + Path.DirectorySeparatorChar + ".git" + Path.DirectorySeparatorChar + "MERGE_HEAD";
return File.Exists(checkFile);
}
/// <summary>
/// Returns the git status "X" key code for a file
/// </summary>
public char Xcode(string file)
{
return XY.ContainsKey(file) ? XY[file][0] : ' ';
}
/// <summary>
/// Returns the git status "Y" key code for a file
/// </summary>
public char Ycode(string file)
{
return XY.ContainsKey(file) ? XY[file][1] : ' ';
}
/// <summary>
/// Returns true if any of the files in any of the subfolders (any descendant)
/// has any modification (addition, update, delete, rename, unmerged, ...)
/// </summary>
public bool HasModifiedDescendants(string key)
{
bool modified = false;
foreach(KeyValuePair<string, string> entry in XY)
{
// skip non-descendants
if (!entry.Key.StartsWith (key))
continue;
if (entry.Value[0] != ' ' || entry.Value[1] != ' ') {
modified = true;
}
}
return modified;
}
/// <summary>
/// Returns the alternate file name associated with the given file
/// </summary>
public string GetAltFile(string key)
{
return AltFile.ContainsKey(key) ? AltFile[key] : string.Empty;
}
/// <summary>
/// Display the info from the given tree node on the main application status pane.
/// </summary>
public void ShowTreeInfo(TreeNode tn)
{
// Translation of git status codes into useful human readable strings
Dictionary<char, string> desc = new Dictionary<char, string> {
{ ' ', "OK" },
{ 'M', "Modified" },
{ 'A', "Added" },
{ 'D', "Deleted" },
{ 'R', "Renamed" },
{ 'C', "Copied" },
{ 'U', "Unmerged" },
{ '?', "Untracked" },
{ '!', "Ignored" } };
string status = "";
if (tn != null)
{
string name = tn.Tag.ToString();
#if DEBUG
status = String.Format("{0} Tag:'{1}': ", tn.Tag.GetType(), name);
#endif
if (IsMarked(name))
{
char xcode = Xcode(name);
char ycode = Ycode(name);
string x = "", y = "";
if (ycode != ' ')
y = desc[ycode];
if (xcode != ' ' && xcode != '?')
x = ((ycode!=' ')? ", " : "") + desc[xcode] + " in index";
status += name + ((x.Length>0 || y.Length>0) ? " ... <" + y + x + ">" : "");
}
}
App.MainForm.SetStatusText(status);
}
}
}