/** * Creates an in-memory index of the ticket change. * * @param changeId * @param change * @return an in-memory index * @throws IOException */ private DirCache createIndex(Repository db, long ticketId, Change change) throws IOException, ClassNotFoundException, NoSuchFieldException { String ticketPath = toTicketPath(ticketId); DirCache newIndex = DirCache.newInCore(); DirCacheBuilder builder = newIndex.builder(); Set<String> ignorePaths = new TreeSet<String>(); try (ObjectInserter inserter = db.newObjectInserter()) { // create/update the journal // exclude the attachment content List<Change> changes = getJournal(db, ticketId); changes.add(change); String journal = TicketSerializer.serializeJournal(changes).trim(); byte[] journalBytes = journal.getBytes(Constants.ENCODING); String journalPath = ticketPath + "/" + JOURNAL; final DirCacheEntry journalEntry = new DirCacheEntry(journalPath); journalEntry.setLength(journalBytes.length); journalEntry.setLastModified(change.date.getTime()); journalEntry.setFileMode(FileMode.REGULAR_FILE); journalEntry.setObjectId( inserter.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, journalBytes)); // add journal to index builder.add(journalEntry); ignorePaths.add(journalEntry.getPathString()); // Add any attachments to the index if (change.hasAttachments()) { for (Attachment attachment : change.attachments) { // build a path name for the attachment and mark as ignored String path = toAttachmentPath(ticketId, attachment.name); ignorePaths.add(path); // create an index entry for this attachment final DirCacheEntry entry = new DirCacheEntry(path); entry.setLength(attachment.content.length); entry.setLastModified(change.date.getTime()); entry.setFileMode(FileMode.REGULAR_FILE); // insert object entry.setObjectId( inserter.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, attachment.content)); // add to temporary in-core index builder.add(entry); } } for (DirCacheEntry entry : getTreeEntries(db, ignorePaths)) { builder.add(entry); } // finish the index builder.finish(); } return newIndex; }
/** * Returns the journal for the specified ticket. * * @param db * @param ticketId * @return a list of changes */ private List<Change> getJournal(Repository db, long ticketId) { RefModel ticketsBranch = getTicketsBranch(db); if (ticketsBranch == null) { return new ArrayList<Change>(); } if (ticketId <= 0L) { return new ArrayList<Change>(); } String journalPath = toTicketPath(ticketId) + "/" + JOURNAL; String json = readTicketsFile(db, journalPath); if (StringUtils.isEmpty(json)) { return new ArrayList<Change>(); } List<Change> list = TicketSerializer.deserializeJournal(json); return list; }
/** * Returns all the tickets in the repository. Querying tickets from the repository requires * deserializing all tickets. This is an expensive process and not recommended. Tickets are * indexed by Lucene and queries should be executed against that index. * * @param repository * @param filter optional filter to only return matching results * @return a list of tickets */ @Override public List<TicketModel> getTickets(RepositoryModel repository, TicketFilter filter) { List<TicketModel> list = new ArrayList<TicketModel>(); Repository db = repositoryManager.getRepository(repository.name); try { RefModel ticketsBranch = getTicketsBranch(db); if (ticketsBranch == null) { return list; } // Collect the set of all json files List<PathModel> paths = JGitUtils.getDocuments(db, Arrays.asList("json"), BRANCH); // Deserialize each ticket and optionally filter out unwanted tickets for (PathModel path : paths) { String name = path.name.substring(path.name.lastIndexOf('/') + 1); if (!JOURNAL.equals(name)) { continue; } String json = readTicketsFile(db, path.path); if (StringUtils.isEmpty(json)) { // journal was touched but no changes were written continue; } try { // Reconstruct ticketId from the path // id/26/326/journal.json String tid = path.path.split("/")[2]; long ticketId = Long.parseLong(tid); List<Change> changes = TicketSerializer.deserializeJournal(json); if (ArrayUtils.isEmpty(changes)) { log.warn("Empty journal for {}:{}", repository, path.path); continue; } TicketModel ticket = TicketModel.buildTicket(changes); ticket.project = repository.projectPath; ticket.repository = repository.name; ticket.number = ticketId; // add the ticket, conditionally, to the list if (filter == null) { list.add(ticket); } else { if (filter.accept(ticket)) { list.add(ticket); } } } catch (Exception e) { log.error( "failed to deserialize {}/{}\n{}", new Object[] {repository, path.path, e.getMessage()}); log.error(null, e); } } // sort the tickets by creation Collections.sort(list); return list; } finally { db.close(); } }