Updating linux build.
[Widgit.git] / Git / Repo.cs
bloba848e046f04efcc05dcb9ad659edb01c0b4eddba
1 //Widgit is free software; you can redistribute it and/or modify
2 //it under the terms of the GNU General Public License as published by
3 //the Free Software Foundation; either version 2 of the License, or
4 //(at your option) any later version.
6 //Widgit is distributed in the hope that it will be useful,
7 //but WITHOUT ANY WARRANTY; without even the implied warranty of
8 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 //GNU General Public License for more details.
11 //You should have received a copy of the GNU General Public License
12 //along with Widgit; if not, write to the Free Software
13 //Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System;
15 using System;
16 using System.Collections.Generic;
17 using System.Text;
19 namespace Git
21 using PathToGitFile = Dictionary<string, Git.File>;
22 public class Repo
24 Branch m_CurrentBranch = null;
25 public Branch CurrentBranch { get { return m_CurrentBranch; } }
27 List<Branch> m_branches = new List<Branch>();
28 public List<Branch> Branches { get { return new List<Branch>(m_branches); } }
30 Tree m_workingSet = null;
31 public Tree WorkingSet { get { return m_workingSet; } }
33 List<Remote> m_remotes = new List<Remote>();
34 public List<Remote> Remotes { get { return new List<Remote>(m_remotes); } }
36 List<Tag> m_tags = new List<Tag>();
37 public List<Tag> Tags { get { return new List<Tag>(m_tags); } }
39 string m_path;
40 public string Path { get { return m_path; } }
42 public static string DirectorySeparator { get { return "/"; } } //git-ls always uses "/"
44 protected static bool m_mono = Type.GetType ("Mono.Runtime") != null;
45 public static bool Mono { get { return m_mono; } }
47 protected static string[] m_lineSep = { System.Environment.NewLine };
48 public static string[] LineSeparator { get { return m_lineSep; } }
50 protected PathToGitFile m_knownFiles;
52 protected string m_gitDir;
53 public string GitDir
55 get
57 if (String.IsNullOrEmpty(m_gitDir))
59 if (!ValidateRepo())
61 return null;
64 return m_gitDir;
68 public Repo(string path)
70 m_path = path;
71 if (UpdateBranches())
73 UpdateTags();
77 protected bool ValidateRepo()
79 return ValidateRepo(m_path, out m_gitDir);
82 public static bool ValidateRepo(string path)
84 string output;
85 return ValidateRepo(path, out output);
88 public static bool ValidateRepo(string path, out string dir)
90 Executioner e = Executioner.GetExecutioner(path, false);
91 string error;
92 bool retval = 0 == e.Execute("git-rev-parse", "--git-dir", "", out dir, out error);
93 dir = dir.Trim();
94 return retval;
97 public bool Init()
99 if (ValidateRepo())
101 return true;
103 Executioner e = Executioner.GetExecutioner(m_path);
104 return 0 == e.Execute("git-init-db");
107 public bool Commit(string message, string[] signedOff, out Commit commited)
109 throw new NotImplementedException();
112 public bool GetFiles(List<string> paths, out List<File> files)
114 if (paths.Count < 1)
116 files = new List<Git.File>();
117 return true;
120 paths[0] = "\"" + paths[0];
121 paths[paths.Count - 1] = paths[paths.Count - 1] + "\"";
122 string pathset = String.Join("\" \"", paths.ToArray());
123 string input = "-c -d -m -o -t -z -k " + pathset;
124 string output, error;
125 Dictionary<string, File> filesMap = new Dictionary<string, File>();
126 Executioner e = Executioner.GetExecutioner(m_path);
127 if (0 == e.Execute("git-ls-files", input, "", out output, out error))
129 ParseLSOutput(output, filesMap);
130 DiffIndex(filesMap, pathset);
131 files = new List<Git.File>(filesMap.Values);
132 return true;
134 files = null;
135 return false;
138 public bool Add(List<string> paths, out List<File> files)
140 Executioner e = Executioner.GetExecutioner(m_path);
141 files = null;
142 string input = String.Join("\n", paths.ToArray());
143 string output, error;
144 if (e.Execute("git-update-index", "--add --stdin", input, out output, out error) == 0)
146 return GetFiles(paths, out files);
148 return false;
151 protected string GetPathsList(List<string> paths)
153 List<string> pathsCopy = new List<string>(paths);
154 pathsCopy[0] = " \"" + pathsCopy[0];
155 pathsCopy[paths.Count - 1] = pathsCopy[paths.Count - 1] + "\"";
156 return String.Join("\" \"", pathsCopy.ToArray());
159 public bool Revert(List<string> paths, out List<File> files)
161 if (paths.Count < 1)
163 files = new List<File>();
164 return true;
166 Executioner e = Executioner.GetExecutioner(m_path);
168 string input = String.Join("\n", paths.ToArray());
169 string output, error;
171 if (e.Execute("git-update-index", "--add --remove --stdin", input, out output, out error) == 0 &&
172 e.Execute("git-update-index", "--refresh") == 0)
174 return GetFiles(paths, out files);
176 files = null;
177 return false;
180 public bool Remove(List<string> paths, out List<File> files)
182 if (paths.Count < 1)
184 files = new List<File>();
185 return true;
187 Executioner e = Executioner.GetExecutioner(m_path);
189 string input = GetPathsList(paths);
190 if (e.Execute("git-rm", "--cached -f " + input) == 0)
192 return GetFiles(paths, out files);
194 files = null;
195 return false;
198 public bool Checkout(Treeish t)
200 if (!t.Verify())
202 return false;
204 Executioner e = Executioner.GetExecutioner(m_path);
205 return 0 == e.Execute("git-checkout", t.ID);
208 public bool Checkout(Tag t, string newBranchName)
210 if (!t.Verify())
212 return false;
214 Executioner e = Executioner.GetExecutioner(m_path);
215 if (0 == e.Execute("git-checkout", "-b " + newBranchName + " " + t.Name))
217 UpdateBranches();
218 return true;
220 return false;
223 protected bool UpdateBranches()
225 Executioner e = Executioner.GetExecutioner(m_path, false);
226 string output, error;
227 if (0 == e.Execute("git-branch", "-v --no-abbrev", "", out output, out error))
229 m_branches.Clear();
230 foreach (string s in output.Split(m_lineSep, StringSplitOptions.RemoveEmptyEntries))
232 string flag = s.Substring(0, 1);
233 int idx = s.IndexOf(" ", 3);
234 string name = s.Substring(2, idx - 2);
235 while (s[idx] == ' ') ++idx;
236 int idx2 = s.IndexOf(" ", idx);
237 string hash = s.Substring(idx, (idx2 - idx));
238 Branch b = new Branch(m_path, name);
239 b.ID = hash;
240 m_branches.Add(b);
241 if (flag == "*")
243 m_CurrentBranch = b;
246 return true;
248 return false;
251 protected bool UpdateTags()
253 Executioner e = Executioner.GetExecutioner(m_path, false);
254 string output = null, error = null;
255 if (0 == e.Execute("git-show-ref", "--tags", "", out output, out error))
257 m_tags.Clear();
258 foreach (string s in output.Split(m_lineSep, StringSplitOptions.RemoveEmptyEntries))
260 string hash = s.Substring(0, 40);
261 string name = s.Substring(41);
262 Tag t = new Tag(name, m_path);
263 t.ID = hash;
264 m_tags.Add(t);
266 return true;
268 return false;
271 public bool NewBranch(string name, Branch startPoint, Remote remote, bool bForce)
273 Executioner e = Executioner.GetExecutioner(m_path);
274 string arguments = name;
275 if (bForce)
277 arguments = arguments + " -f";
279 if (null != startPoint)
281 arguments = arguments + " " + startPoint.Name;
283 if (null != remote)
285 arguments = arguments + " --track " + remote.Name;
287 bool retval = 0 == e.Execute("git-branch", arguments);
288 UpdateBranches();
289 return retval;
292 public bool RenameBranch(Branch b, string newName, bool bForce)
294 Executioner e = Executioner.GetExecutioner(m_path);
295 bool retval = 0 == e.Execute("git-branch", bForce ? "-M " : "-m " + b.Name + " " + newName);
296 UpdateBranches();
297 return retval;
300 public bool DeleteBranch(Branch b, bool bForce)
302 Executioner e = Executioner.GetExecutioner(m_path);
303 bool retval = 0 == e.Execute("git-branch", bForce ? "-D " : "-d " + b.Name);
304 UpdateBranches();
305 return retval;
308 public List<File> ListFiles(bool bJustUnmanaged)
310 Executioner e = Executioner.GetExecutioner(m_path, true);
311 string output, error;
312 Dictionary<string, File> files = new Dictionary<string, File>();
313 string args = bJustUnmanaged ? "-t -o -z" : "-c -d -m -o -k -t -z";
314 if (0 == e.Execute("git-ls-files", args, "", out output, out error))
316 ParseLSOutput(output, files);
318 return new List<File>(files.Values);
321 public void DiffIndex(Dictionary<string, File> filesMap, string paths)
323 Executioner e = Executioner.GetExecutioner(m_path, true);
324 string output, error;
325 if (0 == e.Execute("git-diff-index", "-B -M -C -z --name-status HEAD " + paths, "", out output, out error))
327 string[] lines = output.Split("\0".ToCharArray());
328 for (int i = 0; i < lines.Length - 1; i += 2)
330 string front = lines[i][0].ToString();
331 string file = lines[i + 1].Trim();
332 if (file.StartsWith("\""))
334 file = file.Substring(1);
336 if (file.EndsWith("\""))
338 file = file.Substring(0, file.Length - 1);
340 UpdateMap(filesMap, front, file);
341 if (front == "R")
343 string file2 = lines[i + 2];
344 UpdateMap(filesMap, "R", file2);
345 ++i;
347 if (front == "C")
349 string file2 = lines[i + 2];
350 UpdateMap(filesMap, "A", file2);
351 ++i;
357 private Git.File UpdateMap(Dictionary<string, File> filesMap, string type, string file)
359 Git.File f;
360 if (!filesMap.TryGetValue(file, out f))
362 f = new Git.File(m_path, file);
363 filesMap.Add(file, f);
365 f.SetState(type);
366 return f;
369 private void ParseLSOutput(string output, Dictionary<string, File> files)
371 string[] lines = output.Split("\0".ToCharArray());
372 System.Console.WriteLine("path: " + m_path + " files: " + lines.Length);
373 foreach (string oneline in lines)
375 string line = oneline.Trim();
376 if (line.Length < 3)
378 continue;
381 string front = line[0].ToString();
382 line = line.Substring(2);
383 if (line.StartsWith("\""))
385 line = line.Substring(1);
387 if (line.EndsWith("\""))
389 line = line.Substring(0, line.Length - 1);
391 File f;
392 if (!files.TryGetValue(line, out f))//work around git reporting files twice sometimes
394 f = new File(m_path, line);
395 files.Add(line, f);
397 if (front == "?")
399 f.State = FileState.Unknown;
401 else
403 f.State = FileState.Normal;
408 public bool Reset(string commit)
410 Executioner e = Executioner.GetExecutioner(m_path);
411 string id = null == commit ? "HEAD" : commit;
412 return (0 == e.Execute("git-read-tree", "--reset -u " + id));
415 public bool GetLog(ILogFilter f, out List<Commit> commits)
417 Executioner e = Executioner.GetExecutioner(m_path, true);
418 string args = "-n " + f.Max + Git.Commit.FormatString;
419 if (null != f.Treeish)
421 args += f.Treeish.ID;
423 if (!String.IsNullOrEmpty(f.After))
425 args += " --since=\"" + f.After + "\"";
427 if (!String.IsNullOrEmpty(f.Before))
429 args += " --until=\"" + f.Before + "\"";
431 foreach (string author in f.Authors)
433 args += " --author=\"" + author + "\"";
435 foreach (string path in f.Paths)
437 args += " \"" + path + "\"";
439 string output, error;
440 if (0 == e.Execute("git-log", args, "", out output, out error))
442 string[] records = output.Split(Repo.LineSeparator, StringSplitOptions.RemoveEmptyEntries);
443 commits = new List<Commit>();
444 foreach (string record in records)
446 Commit c = Git.Commit.GetCommit(m_path, record);
447 commits.Add(c);
449 return true;
451 commits = null;
452 return false;
455 public bool GetFilesMap(out PathToGitFile map, bool bForceUpdate)
457 if (null == m_knownFiles || bForceUpdate)
459 m_knownFiles = new PathToGitFile();
460 List<Git.File> unmanagedFiles = ListFiles(true);
461 foreach (Git.File f in unmanagedFiles)
463 m_knownFiles.Add(f.PathWithName, f);
465 DiffIndex(m_knownFiles, "");
467 map = new PathToGitFile(m_knownFiles);
468 return true;