Changed to using gid-diff-index for getting file states.
[Widgit.git] / Git / Repo.cs
blobea0edd1514e92ede72f30111fe3aadfab0ca8650
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
5 namespace Git
7 public class Repo
9 Branch m_CurrentBranch = null;
10 public Branch CurrentBranch { get { return m_CurrentBranch; } }
12 List<Branch> m_branches = new List<Branch>();
13 public List<Branch> Branches { get { return new List<Branch>(m_branches); } }
15 Tree m_workingSet = null;
16 public Tree WorkingSet { get { return m_workingSet; } }
18 List<Remote> m_remotes = new List<Remote>();
19 public List<Remote> Remotes { get { return new List<Remote>(m_remotes); } }
21 List<Tag> m_tags = new List<Tag>();
22 public List<Tag> Tags { get { return new List<Tag>(m_tags); } }
24 string m_path;
25 public string Path { get { return m_path; } }
27 public static string DirectorySeparator { get { return "/"; } } //git-ls always uses "/"
29 protected static bool m_mono = Type.GetType ("Mono.Runtime") != null;
30 public static bool Mono { get { return m_mono; } }
32 protected static string[] m_lineSep = { System.Environment.NewLine };
33 public static string[] LineSeparator { get { return m_lineSep; } }
35 public Repo(string path)
37 m_path = path;
38 if (UpdateBranches())
40 UpdateTags();
44 protected bool ValidateRepo()
46 return ValidateRepo(m_path);
49 public static bool ValidateRepo(string path)
51 Executioner e = Executioner.GetExecutioner(path, false);
53 return 0 == e.Execute("git-rev-parse", "--git-dir");
56 public bool Init()
58 if (ValidateRepo())
60 return true;
62 Executioner e = Executioner.GetExecutioner(m_path);
63 return 0 == e.Execute("git-init-db");
66 public bool Commit(string message, string[] signedOff, out Commit commited)
68 throw new NotImplementedException();
71 public bool GetFiles(List<string> paths, out List<File> files)
73 if (paths.Count < 1)
75 files = new List<Git.File>();
76 return true;
79 paths[0] = "\"" + paths[0];
80 paths[paths.Count - 1] = paths[paths.Count - 1] + "\"";
81 string pathset = String.Join("\" \"", paths.ToArray());
82 string input = "-c -d -m -o -t -z -k " + pathset;
83 string output, error;
84 Dictionary<string, File> filesMap = new Dictionary<string, File>();
85 Executioner e = Executioner.GetExecutioner(m_path);
86 if (0 == e.Execute("git-ls-files", input, "", out output, out error))
88 ParseLSOutput(output, filesMap);
89 UpdateFromIndex(filesMap, pathset);
90 files = new List<Git.File>(filesMap.Values);
91 return true;
93 files = null;
94 return false;
97 public bool Add(List<string> paths, out List<File> files)
99 Executioner e = Executioner.GetExecutioner(m_path);
100 files = null;
101 string input = String.Join("\n", paths.ToArray());
102 string output, error;
103 if (e.Execute("git-update-index", "--add --stdin", input, out output, out error) == 0)
105 return GetFiles(paths, out files);
107 return false;
110 public bool Revert(List<string> paths, out List<File> files)
112 Executioner e = Executioner.GetExecutioner(m_path);
113 files = null;
114 string input = String.Join("\n", paths.ToArray());
115 string output, error;
116 if (e.Execute("git-add", "--add --stdin", input, out output, out error) == 0)
118 return GetFiles(paths, out files);
120 return false;
123 public bool Remove(List<string> paths, out List<File> files)
125 if (paths.Count < 1)
127 files = new List<File>();
128 return true;
130 Executioner e = Executioner.GetExecutioner(m_path);
131 List<string> pathsCopy = new List<string>(paths);
132 paths[0] = " \"" + paths[0];
133 paths[paths.Count - 1] = paths[paths.Count - 1] + "\"";
134 string input = String.Join("\" \"", paths.ToArray());
136 if (e.Execute("git-rm", "--cached -f " + input) == 0)
138 return GetFiles(pathsCopy, out files);
140 files = null;
141 return false;
144 public bool Checkout(Treeish t)
146 if (!t.Verify())
148 return false;
150 Executioner e = Executioner.GetExecutioner(m_path);
151 return 0 == e.Execute("git-checkout", t.ID);
154 public bool Checkout(Tag t, string newBranchName)
156 if (!t.Verify())
158 return false;
160 Executioner e = Executioner.GetExecutioner(m_path);
161 if (0 == e.Execute("git-checkout", "-b " + newBranchName + " " + t.Name))
163 UpdateBranches();
164 return true;
166 return false;
169 protected bool UpdateBranches()
171 Executioner e = Executioner.GetExecutioner(m_path, false);
172 string output, error;
173 if (0 == e.Execute("git-branch", "", "", out output, out error))
175 m_branches.Clear();
176 foreach (string s in output.Split(m_lineSep, StringSplitOptions.RemoveEmptyEntries))
178 string branchName = s.Trim();
179 if (branchName.StartsWith("*"))
181 branchName = branchName.Substring(2);
182 branchName = branchName.Trim();
183 m_CurrentBranch = new Branch(m_path, branchName);
184 m_branches.Add(m_CurrentBranch);
186 else
188 m_branches.Add(new Branch(m_path, branchName));
191 return true;
193 return false;
196 protected bool UpdateTags()
198 Executioner e = Executioner.GetExecutioner(m_path, false);
199 string output = null, error = null;
200 if (0 == e.Execute("git-rev-parse", "--symbolic --tags", "", out output, out error))
202 m_tags.Clear();
203 foreach (string s in output.Split(m_lineSep, StringSplitOptions.RemoveEmptyEntries))
205 m_tags.Add(new Tag(s.Trim(), m_path));
207 return true;
209 return false;
212 public bool NewBranch(string name, Branch startPoint, Remote remote, bool bForce)
214 Executioner e = Executioner.GetExecutioner(m_path);
215 string arguments = name;
216 if (bForce)
218 arguments = arguments + " -f";
220 if (null != startPoint)
222 arguments = arguments + " " + startPoint.Name;
224 if (null != remote)
226 arguments = arguments + " --track " + remote.Name;
228 bool retval = 0 == e.Execute("git-branch", arguments);
229 UpdateBranches();
230 return retval;
233 public bool RenameBranch(Branch b, string newName, bool bForce)
235 Executioner e = Executioner.GetExecutioner(m_path);
236 bool retval = 0 == e.Execute("git-branch", bForce ? "-M " : "-m " + b.Name + " " + newName);
237 UpdateBranches();
238 return retval;
241 public bool DeleteBranch(Branch b, bool bForce)
243 Executioner e = Executioner.GetExecutioner(m_path);
244 bool retval = 0 == e.Execute("git-branch", bForce ? "-D " : "-d " + b.Name);
245 UpdateBranches();
246 return retval;
249 public List<File> ListFiles()
251 Executioner e = Executioner.GetExecutioner(m_path, true);
252 string output, error;
253 Dictionary<string, File> files = new Dictionary<string, File>();
254 if (0 == e.Execute("git-ls-files", "-c -d -m -o -k -t -z", "", out output, out error))
256 ParseLSOutput(output, files);
258 UpdateFromIndex(files, "");
259 return new List<File>(files.Values);
262 private void UpdateFromIndex(Dictionary<string, File> filesMap, string paths)
264 Executioner e = Executioner.GetExecutioner(m_path, true);
265 string output, error;
266 if (0 == e.Execute("git-diff-index", "-B -M -C -z --name-status HEAD " + paths, "", out output, out error))
268 string[] lines = output.Split("\0".ToCharArray());
269 for (int i = 0; i < lines.Length - 1; i += 2)
271 string front = lines[i][0].ToString();
272 string file = lines[i + 1].Trim();
273 if (file.StartsWith("\""))
275 file = file.Substring(1);
277 if (file.EndsWith("\""))
279 file = file.Substring(0, file.Length - 1);
281 Git.File f;
282 if (filesMap.TryGetValue(file, out f))
284 f.SetState(front);
290 private void ParseLSOutput(string output, Dictionary<string, File> files)
292 string[] lines = output.Split("\0".ToCharArray());
293 System.Console.WriteLine("path: " + m_path + " files: " + lines.Length);
294 foreach (string oneline in lines)
296 string line = oneline.Trim();
297 if (line.Length < 3)
299 continue;
302 string front = line[0].ToString();
303 line = line.Substring(2);
304 if (line.StartsWith("\""))
306 line = line.Substring(1);
308 if (line.EndsWith("\""))
310 line = line.Substring(0, line.Length - 1);
312 File f;
313 if (!files.TryGetValue(line, out f))//work around git reporting files twice sometimes
315 f = new File(null, line);
316 files.Add(line, f);
318 if (front == "?")
320 f.State = FileState.Unknown;
322 else
324 f.State = FileState.Normal;