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;
16 using System
.Collections
.Generic
;
21 using PathToGitFile
= Dictionary
<string, Git
.File
>;
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); }
}
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
;
57 if (String
.IsNullOrEmpty(m_gitDir
))
68 public Repo(string path
)
77 protected bool ValidateRepo()
79 return ValidateRepo(m_path
, out m_gitDir
);
82 public static bool ValidateRepo(string path
)
85 return ValidateRepo(path
, out output
);
88 public static bool ValidateRepo(string path
, out string dir
)
90 Executioner e
= Executioner
.GetExecutioner(path
, false);
92 bool retval
= 0 == e
.Execute("git-rev-parse", "--git-dir", "", out dir
, out error
);
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
)
116 files
= new List
<Git
.File
>();
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
);
138 public bool Add(List
<string> paths
, out List
<File
> files
)
140 Executioner e
= Executioner
.GetExecutioner(m_path
);
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
);
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
)
163 files
= new List
<File
>();
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
);
180 public bool Remove(List
<string> paths
, out List
<File
> files
)
184 files
= new List
<File
>();
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
);
198 public bool Checkout(Treeish t
)
204 Executioner e
= Executioner
.GetExecutioner(m_path
);
205 return 0 == e
.Execute("git-checkout", t
.ID
);
208 public bool Checkout(Tag t
, string newBranchName
)
214 Executioner e
= Executioner
.GetExecutioner(m_path
);
215 if (0 == e
.Execute("git-checkout", "-b " + newBranchName
+ " " + t
.Name
))
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
))
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
);
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
))
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
);
271 public bool NewBranch(string name
, Branch startPoint
, Remote remote
, bool bForce
)
273 Executioner e
= Executioner
.GetExecutioner(m_path
);
274 string arguments
= name
;
277 arguments
= arguments
+ " -f";
279 if (null != startPoint
)
281 arguments
= arguments
+ " " + startPoint
.Name
;
285 arguments
= arguments
+ " --track " + remote
.Name
;
287 bool retval
= 0 == e
.Execute("git-branch", arguments
);
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
);
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
);
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
);
343 string file2
= lines
[i
+ 2];
344 UpdateMap(filesMap
, "R", file2
);
349 string file2
= lines
[i
+ 2];
350 UpdateMap(filesMap
, "A", file2
);
357 private Git
.File
UpdateMap(Dictionary
<string, File
> filesMap
, string type
, string file
)
360 if (!filesMap
.TryGetValue(file
, out f
))
362 f
= new Git
.File(m_path
, file
);
363 filesMap
.Add(file
, 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();
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);
392 if (!files
.TryGetValue(line
, out f
))//work around git reporting files twice sometimes
394 f
= new File(m_path
, line
);
399 f
.State
= FileState
.Unknown
;
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
);
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
);