You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

JGitUtils.java 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. package com.gitblit.utils;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.File;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.RandomAccessFile;
  7. import java.text.DateFormat;
  8. import java.text.ParseException;
  9. import java.text.SimpleDateFormat;
  10. import java.util.ArrayList;
  11. import java.util.Collections;
  12. import java.util.Date;
  13. import java.util.HashMap;
  14. import java.util.List;
  15. import java.util.Map;
  16. import java.util.Set;
  17. import org.eclipse.jgit.diff.DiffEntry;
  18. import org.eclipse.jgit.diff.DiffFormatter;
  19. import org.eclipse.jgit.diff.RawTextComparator;
  20. import org.eclipse.jgit.errors.ConfigInvalidException;
  21. import org.eclipse.jgit.lib.AnyObjectId;
  22. import org.eclipse.jgit.lib.Constants;
  23. import org.eclipse.jgit.lib.FileMode;
  24. import org.eclipse.jgit.lib.ObjectId;
  25. import org.eclipse.jgit.lib.ObjectLoader;
  26. import org.eclipse.jgit.lib.PersonIdent;
  27. import org.eclipse.jgit.lib.Ref;
  28. import org.eclipse.jgit.lib.Repository;
  29. import org.eclipse.jgit.lib.StoredConfig;
  30. import org.eclipse.jgit.revwalk.RevBlob;
  31. import org.eclipse.jgit.revwalk.RevCommit;
  32. import org.eclipse.jgit.revwalk.RevObject;
  33. import org.eclipse.jgit.revwalk.RevTree;
  34. import org.eclipse.jgit.revwalk.RevWalk;
  35. import org.eclipse.jgit.treewalk.TreeWalk;
  36. import org.eclipse.jgit.treewalk.filter.PathFilter;
  37. import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
  38. import org.eclipse.jgit.treewalk.filter.TreeFilter;
  39. import org.eclipse.jgit.util.io.DisabledOutputStream;
  40. import org.slf4j.Logger;
  41. import org.slf4j.LoggerFactory;
  42. import com.gitblit.wicket.models.Metric;
  43. import com.gitblit.wicket.models.PathModel;
  44. import com.gitblit.wicket.models.RefModel;
  45. import com.gitblit.wicket.models.TicGitTicket;
  46. import com.gitblit.wicket.models.TicGitTicket.Comment;
  47. public class JGitUtils {
  48. /** Prefix for notes refs */
  49. public static final String R_NOTES = "refs/notes/";
  50. /** Standard notes ref */
  51. public static final String R_NOTES_COMMITS = R_NOTES + "commits";
  52. private final static Logger LOGGER = LoggerFactory.getLogger(JGitUtils.class);
  53. public static List<String> getRepositoryList(File repositoriesFolder, boolean exportAll, boolean readNested) {
  54. List<String> list = new ArrayList<String>();
  55. list.addAll(getNestedRepositories(repositoriesFolder, repositoriesFolder, exportAll, readNested));
  56. Collections.sort(list);
  57. return list;
  58. }
  59. public static List<String> getNestedRepositories(File repositoriesFolder, File folder, boolean exportAll, boolean readNested) {
  60. String basefile = repositoriesFolder.getAbsolutePath();
  61. List<String> list = new ArrayList<String>();
  62. for (File file : folder.listFiles()) {
  63. if (file.isDirectory() && !file.getName().equalsIgnoreCase(Constants.DOT_GIT)) {
  64. // if this is a git repository add it to the list
  65. File gitFolder = new File(file, Constants.DOT_GIT);
  66. boolean isGitRepository = gitFolder.exists() && gitFolder.isDirectory();
  67. boolean exportRepository = isGitRepository && (exportAll || new File(gitFolder, "git-daemon-export-ok").exists());
  68. if (exportRepository) {
  69. // determine repository name relative to repositories folder
  70. String filename = file.getAbsolutePath();
  71. String repo = filename.substring(basefile.length()).replace('\\', '/');
  72. if (repo.charAt(0) == '/') {
  73. repo = repo.substring(1);
  74. }
  75. list.add(repo);
  76. }
  77. // look for nested repositories
  78. if (readNested) {
  79. list.addAll(getNestedRepositories(repositoriesFolder, file, exportAll, readNested));
  80. }
  81. }
  82. }
  83. return list;
  84. }
  85. public static Date getLastChange(Repository r) {
  86. RevCommit commit = getCommit(r, Constants.HEAD);
  87. return getCommitDate(commit);
  88. }
  89. public static RevCommit getCommit(Repository r, String objectId) {
  90. RevCommit commit = null;
  91. try {
  92. if (objectId == null || objectId.trim().length() == 0) {
  93. objectId = Constants.HEAD;
  94. }
  95. ObjectId object = r.resolve(objectId);
  96. RevWalk walk = new RevWalk(r);
  97. RevCommit rev = walk.parseCommit(object);
  98. commit = rev;
  99. walk.dispose();
  100. } catch (Throwable t) {
  101. LOGGER.error("Failed to determine last change", t);
  102. }
  103. return commit;
  104. }
  105. public static Map<ObjectId, List<String>> getAllRefs(Repository r) {
  106. Map<ObjectId, List<String>> refs = new HashMap<ObjectId, List<String>>();
  107. Map<AnyObjectId, Set<Ref>> allRefs = r.getAllRefsByPeeledObjectId();
  108. for (AnyObjectId id : allRefs.keySet()) {
  109. List<String> list = new ArrayList<String>();
  110. for (Ref setRef : allRefs.get(id)) {
  111. String name = setRef.getName();
  112. list.add(name);
  113. }
  114. refs.put(id.toObjectId(), list);
  115. }
  116. return refs;
  117. }
  118. public static Map<ObjectId, List<String>> getRefs(Repository r, String baseRef) {
  119. Map<ObjectId, List<String>> refs = new HashMap<ObjectId, List<String>>();
  120. Map<AnyObjectId, Set<Ref>> allRefs = r.getAllRefsByPeeledObjectId();
  121. for (AnyObjectId id : allRefs.keySet()) {
  122. List<String> list = new ArrayList<String>();
  123. for (Ref setRef : allRefs.get(id)) {
  124. String name = setRef.getName();
  125. if (name.startsWith(baseRef)) {
  126. list.add(name);
  127. }
  128. }
  129. refs.put(id.toObjectId(), list);
  130. }
  131. return refs;
  132. }
  133. /**
  134. * Lookup an entry stored in a tree, failing if not present.
  135. *
  136. * @param tree
  137. * the tree to search.
  138. * @param path
  139. * the path to find the entry of.
  140. * @return the parsed object entry at this path
  141. * @throws Exception
  142. */
  143. public static RevObject getRevObject(Repository r, final RevTree tree, final String path) {
  144. RevObject ro = null;
  145. RevWalk rw = new RevWalk(r);
  146. TreeWalk tw = new TreeWalk(r);
  147. tw.setFilter(PathFilterGroup.createFromStrings(Collections.singleton(path)));
  148. try {
  149. tw.reset(tree);
  150. while (tw.next()) {
  151. if (tw.isSubtree() && !path.equals(tw.getPathString())) {
  152. tw.enterSubtree();
  153. continue;
  154. }
  155. ObjectId entid = tw.getObjectId(0);
  156. FileMode entmode = tw.getFileMode(0);
  157. ro = rw.lookupAny(entid, entmode.getObjectType());
  158. rw.parseBody(ro);
  159. }
  160. } catch (Throwable t) {
  161. LOGGER.error("Can't find " + path + " in tree " + tree.name(), t);
  162. } finally {
  163. if (rw != null) {
  164. rw.dispose();
  165. }
  166. }
  167. return ro;
  168. }
  169. public static byte[] getRawContent(Repository r, RevBlob blob) {
  170. ByteArrayOutputStream os = new ByteArrayOutputStream();
  171. try {
  172. ObjectLoader ldr = r.open(blob.getId(), Constants.OBJ_BLOB);
  173. byte[] tmp = new byte[1024];
  174. InputStream in = ldr.openStream();
  175. int n;
  176. while ((n = in.read(tmp)) > 0) {
  177. os.write(tmp, 0, n);
  178. }
  179. in.close();
  180. } catch (Throwable t) {
  181. LOGGER.error("Failed to read raw content", t);
  182. }
  183. return os.toByteArray();
  184. }
  185. public static String getRawContentAsString(Repository r, RevBlob blob) {
  186. return new String(getRawContent(r, blob));
  187. }
  188. public static String getRawContentAsString(Repository r, RevCommit commit, String blobPath) {
  189. RevObject obj = getRevObject(r, commit.getTree(), blobPath);
  190. return new String(getRawContent(r, (RevBlob) obj));
  191. }
  192. public static List<PathModel> getFilesInPath(Repository r, String basePath, String objectId) {
  193. RevCommit commit = getCommit(r, objectId);
  194. return getFilesInPath(r, basePath, commit);
  195. }
  196. public static List<PathModel> getFilesInPath(Repository r, String basePath, RevCommit commit) {
  197. List<PathModel> list = new ArrayList<PathModel>();
  198. final TreeWalk walk = new TreeWalk(r);
  199. try {
  200. walk.addTree(commit.getTree());
  201. if (basePath != null && basePath.length() > 0) {
  202. PathFilter f = PathFilter.create(basePath);
  203. walk.setFilter(f);
  204. walk.setRecursive(false);
  205. boolean foundFolder = false;
  206. while (walk.next()) {
  207. if (!foundFolder && walk.isSubtree()) {
  208. walk.enterSubtree();
  209. }
  210. if (walk.getPathString().equals(basePath)) {
  211. foundFolder = true;
  212. continue;
  213. }
  214. if (foundFolder) {
  215. list.add(getPathModel(walk, basePath, commit));
  216. }
  217. }
  218. } else {
  219. walk.setRecursive(false);
  220. while (walk.next()) {
  221. list.add(getPathModel(walk, null, commit));
  222. }
  223. }
  224. } catch (IOException e) {
  225. LOGGER.error("Failed to get files for commit " + commit.getName(), e);
  226. } finally {
  227. walk.release();
  228. }
  229. Collections.sort(list);
  230. return list;
  231. }
  232. public static List<PathModel> getFilesInCommit(Repository r, String commitId) {
  233. RevCommit commit = getCommit(r, commitId);
  234. return getFilesInCommit(r, commit);
  235. }
  236. public static List<PathModel> getFilesInCommit(Repository r, RevCommit commit) {
  237. List<PathModel> list = new ArrayList<PathModel>();
  238. try {
  239. final RevWalk rw = new RevWalk(r);
  240. RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
  241. RevTree parentTree = parent.getTree();
  242. RevTree commitTree = commit.getTree();
  243. final TreeWalk walk = new TreeWalk(r);
  244. walk.reset();
  245. walk.setRecursive(true);
  246. walk.addTree(parentTree);
  247. walk.addTree(commitTree);
  248. walk.setFilter(TreeFilter.ANY_DIFF);
  249. RawTextComparator cmp = RawTextComparator.DEFAULT;
  250. DiffFormatter df = new DiffFormatter(DisabledOutputStream.INSTANCE);
  251. df.setRepository(r);
  252. df.setDiffComparator(cmp);
  253. df.setDetectRenames(true);
  254. List<DiffEntry> diffs = df.scan(parentTree, commitTree);
  255. for (DiffEntry diff : diffs) {
  256. list.add(new PathModel(diff.getNewPath(), diff.getNewPath(), 0, diff.getNewMode().getBits(), commit.getId().getName()));
  257. }
  258. } catch (Throwable t) {
  259. LOGGER.error("failed to determine files in commit!", t);
  260. }
  261. return list;
  262. }
  263. public static String getCommitDiff(Repository r, RevCommit commit, boolean outputHtml) {
  264. return getCommitDiff(r, commit, null, outputHtml);
  265. }
  266. public static String getCommitDiff(Repository r, RevCommit commit, String path, boolean outputHtml) {
  267. try {
  268. final RevWalk rw = new RevWalk(r);
  269. RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
  270. RevTree parentTree = parent.getTree();
  271. RevTree commitTree = commit.getTree();
  272. final TreeWalk walk = new TreeWalk(r);
  273. walk.reset();
  274. walk.setRecursive(true);
  275. walk.addTree(parentTree);
  276. walk.addTree(commitTree);
  277. walk.setFilter(TreeFilter.ANY_DIFF);
  278. final ByteArrayOutputStream os = new ByteArrayOutputStream();
  279. RawTextComparator cmp = RawTextComparator.DEFAULT;
  280. DiffFormatter df;
  281. if (outputHtml) {
  282. df = new HtmlDiffFormatter(os);
  283. } else {
  284. df = new DiffFormatter(os);
  285. }
  286. df.setRepository(r);
  287. df.setDiffComparator(cmp);
  288. df.setDetectRenames(true);
  289. List<DiffEntry> diffs = df.scan(parentTree, commitTree);
  290. if (path != null && path.length() > 0) {
  291. for (DiffEntry diff : diffs) {
  292. if (diff.getNewPath().equalsIgnoreCase(path)) {
  293. df.format(diff);
  294. break;
  295. }
  296. }
  297. } else {
  298. df.format(diffs);
  299. }
  300. String diff;
  301. if (outputHtml) {
  302. // workaround for complex private methods in DiffFormatter
  303. diff = ((HtmlDiffFormatter) df).getHtml();
  304. } else {
  305. diff = os.toString();
  306. }
  307. df.flush();
  308. return diff;
  309. } catch (Throwable t) {
  310. LOGGER.error("failed to generate commit diff!", t);
  311. }
  312. return null;
  313. }
  314. public static String getCommitPatch(Repository r, RevCommit commit) {
  315. return getCommitPatch(r, commit);
  316. }
  317. public static String getCommitPatch(Repository r, RevCommit commit, String path) {
  318. try {
  319. final RevWalk rw = new RevWalk(r);
  320. RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
  321. RevTree parentTree = parent.getTree();
  322. RevTree commitTree = commit.getTree();
  323. final TreeWalk walk = new TreeWalk(r);
  324. walk.reset();
  325. walk.setRecursive(true);
  326. walk.addTree(parentTree);
  327. walk.addTree(commitTree);
  328. walk.setFilter(TreeFilter.ANY_DIFF);
  329. final ByteArrayOutputStream os = new ByteArrayOutputStream();
  330. RawTextComparator cmp = RawTextComparator.DEFAULT;
  331. PatchFormatter df = new PatchFormatter(os);
  332. df.setRepository(r);
  333. df.setDiffComparator(cmp);
  334. df.setDetectRenames(true);
  335. List<DiffEntry> diffs = df.scan(parentTree, commitTree);
  336. if (path != null && path.length() > 0) {
  337. for (DiffEntry diff : diffs) {
  338. if (diff.getNewPath().equalsIgnoreCase(path)) {
  339. df.format(diff);
  340. break;
  341. }
  342. }
  343. } else {
  344. df.format(diffs);
  345. }
  346. String diff = df.getPatch(commit);
  347. df.flush();
  348. return diff;
  349. } catch (Throwable t) {
  350. LOGGER.error("failed to generate commit diff!", t);
  351. }
  352. return null;
  353. }
  354. private static PathModel getPathModel(TreeWalk walk, String basePath, RevCommit commit) {
  355. String name;
  356. long size = 0;
  357. if (basePath == null) {
  358. name = walk.getPathString();
  359. } else {
  360. try {
  361. name = walk.getPathString().substring(basePath.length() + 1);
  362. } catch (Throwable t) {
  363. name = walk.getPathString();
  364. }
  365. }
  366. try {
  367. if (!walk.isSubtree()) {
  368. size = walk.getObjectReader().getObjectSize(walk.getObjectId(0), Constants.OBJ_BLOB);
  369. }
  370. } catch (Throwable t) {
  371. LOGGER.error("Failed to retrieve blob size", t);
  372. }
  373. return new PathModel(name, walk.getPathString(), size, walk.getFileMode(0).getBits(), commit.getName());
  374. }
  375. public static String getPermissionsFromMode(int mode) {
  376. if (FileMode.TREE.equals(mode)) {
  377. return "drwxr-xr-x";
  378. } else if (FileMode.REGULAR_FILE.equals(mode)) {
  379. return "-rw-r--r--";
  380. } else if (FileMode.EXECUTABLE_FILE.equals(mode)) {
  381. return "-rwxr-xr-x";
  382. } else if (FileMode.SYMLINK.equals(mode)) {
  383. // FIXME symlink permissions
  384. return "symlink";
  385. } else if (FileMode.GITLINK.equals(mode)) {
  386. // FIXME gitlink permissions
  387. return "gitlink";
  388. } else if (FileMode.MISSING.equals(mode)) {
  389. // FIXME missing permissions
  390. return "missing";
  391. }
  392. return "" + mode;
  393. }
  394. public static boolean isTreeFromMode(int mode) {
  395. return FileMode.TREE.equals(mode);
  396. }
  397. public static List<RevCommit> getRevLog(Repository r, int maxCount) {
  398. return getRevLog(r, Constants.HEAD, 0, maxCount);
  399. }
  400. public static List<RevCommit> getRevLog(Repository r, String objectId, int offset, int maxCount) {
  401. List<RevCommit> list = new ArrayList<RevCommit>();
  402. try {
  403. if (objectId == null || objectId.trim().length() == 0) {
  404. objectId = Constants.HEAD;
  405. }
  406. RevWalk walk = new RevWalk(r);
  407. ObjectId object = r.resolve(objectId);
  408. walk.markStart(walk.parseCommit(object));
  409. Iterable<RevCommit> revlog = walk;
  410. if (offset > 0) {
  411. int count = 0;
  412. for (RevCommit rev : revlog) {
  413. count++;
  414. if (count > offset) {
  415. list.add(rev);
  416. if (maxCount > 0 && list.size() == maxCount) {
  417. break;
  418. }
  419. }
  420. }
  421. } else {
  422. for (RevCommit rev : revlog) {
  423. list.add(rev);
  424. if (maxCount > 0 && list.size() == maxCount) {
  425. break;
  426. }
  427. }
  428. }
  429. walk.dispose();
  430. } catch (Throwable t) {
  431. LOGGER.error("Failed to determine last change", t);
  432. }
  433. return list;
  434. }
  435. public static List<RefModel> getTags(Repository r, int maxCount) {
  436. return getRefs(r, Constants.R_TAGS, maxCount);
  437. }
  438. public static List<RefModel> getLocalBranches(Repository r, int maxCount) {
  439. return getRefs(r, Constants.R_HEADS, maxCount);
  440. }
  441. public static List<RefModel> getRemoteBranches(Repository r, int maxCount) {
  442. return getRefs(r, Constants.R_REMOTES, maxCount);
  443. }
  444. public static List<RefModel> getRefs(Repository r, String refs, int maxCount) {
  445. List<RefModel> list = new ArrayList<RefModel>();
  446. try {
  447. Map<String, Ref> map = r.getRefDatabase().getRefs(refs);
  448. for (String name : map.keySet()) {
  449. Ref ref = map.get(name);
  450. RevCommit commit = getCommit(r, ref.getObjectId().getName());
  451. list.add(new RefModel(name, ref, commit));
  452. }
  453. Collections.sort(list);
  454. Collections.reverse(list);
  455. if (maxCount > 0 && list.size() > maxCount) {
  456. list = new ArrayList<RefModel>(list.subList(0, maxCount));
  457. }
  458. } catch (IOException e) {
  459. LOGGER.error("Failed to retrieve " + refs, e);
  460. }
  461. return list;
  462. }
  463. public static Ref getRef(Repository r, String id) {
  464. try {
  465. Map<String, Ref> map = r.getRefDatabase().getRefs(id);
  466. for (String name : map.keySet()) {
  467. return map.get(name);
  468. }
  469. } catch (IOException e) {
  470. LOGGER.error("Failed to retrieve ref " + id, e);
  471. }
  472. return null;
  473. }
  474. public static Date getCommitDate(RevCommit commit) {
  475. return new Date(commit.getCommitTime() * 1000l);
  476. }
  477. public static String getDisplayName(PersonIdent person) {
  478. final StringBuilder r = new StringBuilder();
  479. r.append(person.getName());
  480. r.append(" <");
  481. r.append(person.getEmailAddress());
  482. r.append(">");
  483. return r.toString();
  484. }
  485. public static String getRepositoryDescription(Repository r) {
  486. File dir = r.getDirectory();
  487. if (dir.exists()) {
  488. File description = new File(dir, "description");
  489. if (description.exists() && description.length() > 0) {
  490. RandomAccessFile raf = null;
  491. try {
  492. raf = new RandomAccessFile(description, "r");
  493. byte[] buffer = new byte[(int) description.length()];
  494. raf.readFully(buffer);
  495. return new String(buffer);
  496. } catch (Throwable t) {
  497. } finally {
  498. try {
  499. raf.close();
  500. } catch (Throwable t) {
  501. }
  502. }
  503. }
  504. }
  505. return "";
  506. }
  507. public static String getRepositoryOwner(Repository r) {
  508. StoredConfig c = readConfig(r);
  509. if (c == null) {
  510. return "";
  511. }
  512. String o = c.getString("gitweb", null, "owner");
  513. return o == null ? "" : o;
  514. }
  515. private static StoredConfig readConfig(Repository r) {
  516. StoredConfig c = r.getConfig();
  517. if (c != null) {
  518. try {
  519. c.load();
  520. } catch (ConfigInvalidException cex) {
  521. LOGGER.error("Repository configuration is invalid!", cex);
  522. } catch (IOException cex) {
  523. LOGGER.error("Could not open repository configuration!", cex);
  524. }
  525. return c;
  526. }
  527. return null;
  528. }
  529. public static List<Metric> getDateMetrics(Repository r) {
  530. final List<RefModel> tags = getTags(r, -1);
  531. final Map<String, Metric> map = new HashMap<String, Metric>();
  532. try {
  533. DateFormat df = new SimpleDateFormat("yyyy-MM");
  534. RevWalk walk = new RevWalk(r);
  535. ObjectId object = r.resolve(Constants.HEAD);
  536. walk.markStart(walk.parseCommit(object));
  537. Iterable<RevCommit> revlog = walk;
  538. for (RevCommit rev : revlog) {
  539. Date d = getCommitDate(rev);
  540. String p = df.format(d);
  541. if (!map.containsKey(p))
  542. map.put(p, new Metric(p));
  543. map.get(p).count++;
  544. }
  545. } catch (Throwable t) {
  546. LOGGER.error("Failed to mine log history for metrics", t);
  547. }
  548. List<String> keys = new ArrayList<String>(map.keySet());
  549. Collections.sort(keys);
  550. List<Metric> metrics = new ArrayList<Metric>();
  551. for (String key : keys) {
  552. metrics.add(map.get(key));
  553. }
  554. return metrics;
  555. }
  556. public static RefModel getTicGitBranch(Repository r) {
  557. RefModel ticgitBranch = null;
  558. try {
  559. // search for ticgit branch in local heads
  560. for (RefModel ref : getLocalBranches(r, -1)) {
  561. if (ref.getDisplayName().endsWith("ticgit") || ref.getDisplayName().endsWith("ticgit-ng")) {
  562. ticgitBranch = ref;
  563. break;
  564. }
  565. }
  566. // search for ticgit branch in remote heads
  567. if (ticgitBranch == null) {
  568. for (RefModel ref : getRemoteBranches(r, -1)) {
  569. if (ref.getDisplayName().endsWith("ticgit") || ref.getDisplayName().endsWith("ticgit-ng")) {
  570. ticgitBranch = ref;
  571. break;
  572. }
  573. }
  574. }
  575. } catch (Throwable t) {
  576. LOGGER.error("Failed to find ticgit branch!", t);
  577. }
  578. return ticgitBranch;
  579. }
  580. public static List<TicGitTicket> getTicGitTickets(Repository r) {
  581. RefModel ticgitBranch = getTicGitBranch(r);
  582. List<PathModel> paths = getFilesInPath(r, null, ticgitBranch.getCommit());
  583. List<TicGitTicket> tickets = new ArrayList<TicGitTicket>();
  584. for (PathModel ticketFolder : paths) {
  585. if (ticketFolder.isTree()) {
  586. try {
  587. TicGitTicket t = new TicGitTicket(ticketFolder.name);
  588. readTicketContents(r, ticgitBranch, t);
  589. tickets.add(t);
  590. } catch (Throwable t) {
  591. LOGGER.error("Failed to get a ticgit ticket!", t);
  592. }
  593. }
  594. }
  595. Collections.sort(tickets);
  596. Collections.reverse(tickets);
  597. return tickets;
  598. }
  599. public static TicGitTicket getTicGitTicket(Repository r, String ticketFolder) {
  600. RefModel ticgitBranch = getTicGitBranch(r);
  601. if (ticgitBranch != null) {
  602. try {
  603. TicGitTicket ticket = new TicGitTicket(ticketFolder);
  604. readTicketContents(r, ticgitBranch, ticket);
  605. return ticket;
  606. } catch (Throwable t) {
  607. LOGGER.error("Failed to get ticgit ticket " + ticketFolder, t);
  608. }
  609. }
  610. return null;
  611. }
  612. private static void readTicketContents(Repository r, RefModel ticgitBranch, TicGitTicket ticket) {
  613. List<PathModel> ticketFiles = getFilesInPath(r, ticket.name, ticgitBranch.getCommit());
  614. for (PathModel file : ticketFiles) {
  615. String content = getRawContentAsString(r, ticgitBranch.getCommit(), file.path).trim();
  616. if (file.name.equals("TICKET_ID")) {
  617. ticket.id = content;
  618. } else if (file.name.equals("TITLE")) {
  619. ticket.title = content;
  620. } else {
  621. String[] chunks = file.name.split("_");
  622. if (chunks[0].equals("ASSIGNED")) {
  623. ticket.handler = content;
  624. } else if (chunks[0].equals("COMMENT")) {
  625. try {
  626. Comment c = new Comment(file.name, content);
  627. ticket.comments.add(c);
  628. } catch (ParseException e) {
  629. e.printStackTrace();
  630. }
  631. } else if (chunks[0].equals("TAG")) {
  632. if (content.startsWith("TAG_")) {
  633. ticket.tags.add(content.substring(4));
  634. } else {
  635. ticket.tags.add(content);
  636. }
  637. } else if (chunks[0].equals("STATE")) {
  638. ticket.state = content;
  639. }
  640. }
  641. }
  642. Collections.sort(ticket.comments);
  643. }
  644. public static String getTicGitContent(Repository r, String filePath) {
  645. RefModel ticgitBranch = getTicGitBranch(r);
  646. if (ticgitBranch != null) {
  647. return getRawContentAsString(r, ticgitBranch.getCommit(), filePath);
  648. }
  649. return "";
  650. }
  651. }