public static ArrayMemory valueOf(DiffEntry value) { ArrayMemory memory = new ArrayMemory(); memory.refOfIndex("oldId").assign(value.getOldId() == null ? Memory.NULL : valueOf(value.getOldId().toObjectId())); memory.refOfIndex("oldPath").assign(value.getOldPath()); memory.refOfIndex("oldMode").assign(value.getOldMode() == null ? Memory.NULL : StringMemory.valueOf(value.getOldMode().toString())); memory.refOfIndex("newId").assign(value.getNewId() == null ? Memory.NULL : valueOf(value.getNewId().toObjectId())); memory.refOfIndex("newPath").assign(value.getNewPath()); memory.refOfIndex("newMode").assign(value.getNewMode() == null ? Memory.NULL : StringMemory.valueOf(value.getNewMode().toString())); memory.refOfIndex("score").assign(value.getScore()); memory.refOfIndex("changeType").assign(value.getChangeType().name()); return memory; }
/** * Convert the TreeWalk into DiffEntry headers. * * @param walk * the TreeWalk to walk through. Must have exactly two trees. * @return headers describing the changed files. * @throws java.io.IOException * the repository cannot be accessed. * @throws java.lang.IllegalArgumentException * When given TreeWalk doesn't have exactly two trees. */ public static List<DiffEntry> scan(TreeWalk walk) throws IOException { return scan(walk, false); }
/** * Sort the changes in a commit so that changes to node files appear before changes to edge files. This is done so that * node related changes are applied to the FlowGraph before edge related changes. An example where the order matters * is the case when a commit adds a new node n2 as well as adds an edge from an existing node n1 to n2. To ensure that the * addition of edge n1->n2 is successful, node n2 must exist in the graph and so needs to be added first. For deletions, * the order does not matter and ordering the changes in the commit will result in the same FlowGraph state as if the changes * were unordered. In other words, deletion of a node deletes all its incident edges from the FlowGraph. So processing an * edge deletion later results in a no-op. Note that node and edge files do not change depth in case of modifications. * * If there are multiple commits between successive polls to Git, the re-ordering of changes across commits should not * affect the final state of the FlowGraph. This is because, the order of changes for a given file type (i.e. node or edge) * is preserved. */ @Override void processGitConfigChanges() throws GitAPIException, IOException { List<DiffEntry> changes = this.gitRepo.getChanges(); Collections.sort(changes, (o1, o2) -> { Integer o1Depth = (o1.getNewPath() != null) ? (new Path(o1.getNewPath())).depth() : (new Path(o1.getOldPath())).depth(); Integer o2Depth = (o2.getNewPath() != null) ? (new Path(o2.getNewPath())).depth() : (new Path(o2.getOldPath())).depth(); return o1Depth.compareTo(o2Depth); }); processGitConfigChangesHelper(changes); //Decrements the latch count. The countdown latch is initialized to 1. So after the first time the latch is decremented, // the following operation should be a no-op. this.initComplete.countDown(); }
static void nameStatus(ThrowingPrintWriter out, List<DiffEntry> files) throws IOException { for (DiffEntry ent : files) { switch (ent.getChangeType()) { case ADD: out.println("A\t" + ent.getNewPath()); //$NON-NLS-1$ break; case DELETE: out.println("D\t" + ent.getOldPath()); //$NON-NLS-1$ break; case MODIFY: out.println("M\t" + ent.getNewPath()); //$NON-NLS-1$ break; case COPY: out.format("C%1$03d\t%2$s\t%3$s", valueOf(ent.getScore()), // //$NON-NLS-1$ ent.getOldPath(), ent.getNewPath()); out.println(); break; case RENAME: out.format("R%1$03d\t%2$s\t%3$s", valueOf(ent.getScore()), // //$NON-NLS-1$ ent.getOldPath(), ent.getNewPath()); out.println(); break; } } } }
/** * Format index line * * @param o * the stream the formatter will write line data to * @param ent * the DiffEntry to create the FileHeader for * @throws java.io.IOException * writing to the supplied stream failed. */ protected void formatIndexLine(OutputStream o, DiffEntry ent) throws IOException { o.write(encodeASCII("index " // //$NON-NLS-1$ + format(ent.getOldId()) // + ".." // //$NON-NLS-1$ + format(ent.getNewId()))); if (ent.getOldMode().equals(ent.getNewMode())) { o.write(' '); ent.getNewMode().copyTo(o); } o.write('\n'); }
private static void listDiff(Repository repository, Git git, String oldCommit, String newCommit) throws GitAPIException, IOException { final List<DiffEntry> diffs = git.diff() .setOldTree(prepareTreeParser(repository, oldCommit)) .setNewTree(prepareTreeParser(repository, newCommit)) .call(); System.out.println("Found: " + diffs.size() + " differences"); for (DiffEntry diff : diffs) { System.out.println("Diff: " + diff.getChangeType() + ": " + (diff.getOldPath().equals(diff.getNewPath()) ? diff.getNewPath() : diff.getOldPath() + " -> " + diff.getNewPath())); } }
/** * Breaks apart a DiffEntry into two entries, one DELETE and one ADD. * * @param entry * the DiffEntry to break apart. * @return a list containing two entries. Calling {@link #getChangeType()} * on the first entry will return ChangeType.DELETE. Calling it on * the second entry will return ChangeType.ADD. */ static List<DiffEntry> breakModify(DiffEntry entry) { DiffEntry del = new DiffEntry(); del.oldId = entry.getOldId(); del.oldMode = entry.getOldMode(); del.oldPath = entry.getOldPath(); del.newId = A_ZERO; del.newMode = FileMode.MISSING; del.newPath = DiffEntry.DEV_NULL; del.changeType = ChangeType.DELETE; del.diffAttribute = entry.diffAttribute; DiffEntry add = new DiffEntry(); add.oldId = A_ZERO; add.oldMode = FileMode.MISSING; add.oldPath = DiffEntry.DEV_NULL; add.newId = entry.getNewId(); add.newMode = entry.getNewMode(); add.newPath = entry.getNewPath(); add.changeType = ChangeType.ADD; add.diffAttribute = entry.diffAttribute; return Arrays.asList(del, add); }
private void updateFollowFilter(ObjectId[] trees, DiffConfig cfg) throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException, IOException { TreeWalk tw = pathFilter; FollowFilter oldFilter = (FollowFilter) tw.getFilter(); tw.setFilter(TreeFilter.ANY_DIFF); tw.reset(trees); List<DiffEntry> files = DiffEntry.scan(tw); RenameDetector rd = new RenameDetector(tw.getObjectReader(), cfg); rd.addAll(files); files = rd.compute(); TreeFilter newFilter = oldFilter; for (DiffEntry ent : files) { if (isRename(ent) && ent.getNewPath().equals(oldFilter.getPath())) { newFilter = FollowFilter.create(ent.getOldPath(), cfg); RenameCallback callback = oldFilter.getRenameCallback(); if (callback != null) { callback.renamed(ent); // forward the callback to the new follow filter ((FollowFilter) newFilter).setRenameCallback(callback); } break; } } tw.setFilter(newFilter); }
/** * Method creates a diff object to be returned to the client. * * @param diff - DiffEntry * @param git - GitUtil * @return - Diff */ public static Diff createDiff(final DiffEntry diff, final GitUtil git) { try { val id = diff.getChangeType() == DiffEntry.ChangeType.ADD ? diff.getNewId().toObjectId() : diff.getOldId().toObjectId(); val service = CasManagementUtils.fromJson(git.readObject(id)); return new Diff(diff.getNewPath(), diff.getOldId().toObjectId(), diff.getNewId().toObjectId(), diff.getChangeType().toString(), service.getName()); } catch (final Exception e) { LOGGER.error(e.getMessage(), e); return null; } } }
private boolean processOne(Candidate n) throws IOException { RevCommit parent = n.getParent(0); if (parent == null) return split(n.getNextCandidate(0), n); revPool.parseHeaders(parent); if (find(parent, n.sourcePath)) { if (idBuf.equals(n.sourceBlob)) return blameEntireRegionOnParent(n, parent); return splitBlameWithParent(n, parent); } if (n.sourceCommit == null) return result(n); DiffEntry r = findRename(parent, n.sourceCommit, n.sourcePath); if (r == null) return result(n); if (0 == r.getOldId().prefixCompare(n.sourceBlob)) { // A 100% rename without any content change can also // skip directly to the parent. n.sourceCommit = parent; n.sourcePath = PathFilter.create(r.getOldPath()); push(n); return false; } Candidate next = n.create(getRepository(), parent, PathFilter.create(r.getOldPath())); next.sourceBlob = r.getOldId().toObjectId(); next.renameScore = r.getScore(); next.loadText(reader); return split(next, n); }
/** * A helper method where actual processing of the list of changes since the last refresh of the repository takes place * and the changes applied. * @throws IOException */ void processGitConfigChangesHelper(List<DiffEntry> changes) throws IOException { for (DiffEntry change : changes) { switch (change.getChangeType()) { case ADD: case MODIFY: addChange(change); break; case DELETE: removeChange(change); break; case RENAME: removeChange(change); addChange(change); break; default: throw new RuntimeException("Unsupported change type " + change.getChangeType()); } } // Done processing changes, so checkpoint this.gitRepo.moveCheckpointAndHashesForward(); }
private boolean isAdd(List<DiffEntry> files) { String oldPath = ((FollowFilter) pathFilter).getPath(); for (DiffEntry ent : files) { if (ent.getChangeType() == ADD && ent.getNewPath().equals(oldPath)) return true; } return false; }
/** * Add a {@link DataNode} to the {@link FlowGraph}. The method uses the {@link FlowGraphConfigurationKeys#DATA_NODE_CLASS} config * to instantiate a {@link DataNode} from the node config file. * @param change */ private void addDataNode(DiffEntry change) { if (checkFilePath(change.getNewPath(), NODE_FILE_DEPTH)) { Path nodeFilePath = new Path(this.repositoryDir, change.getNewPath()); try { Config config = loadNodeFileWithOverrides(nodeFilePath); Class dataNodeClass = Class.forName(ConfigUtils.getString(config, FlowGraphConfigurationKeys.DATA_NODE_CLASS, FlowGraphConfigurationKeys.DEFAULT_DATA_NODE_CLASS)); DataNode dataNode = (DataNode) GobblinConstructorUtils.invokeLongestConstructor(dataNodeClass, config); if (!this.flowGraph.addDataNode(dataNode)) { log.warn("Could not add DataNode {} to FlowGraph; skipping", dataNode.getId()); } else { log.info("Added Datanode {} to FlowGraph", dataNode.getId()); } } catch (Exception e) { log.warn("Could not add DataNode defined in {} due to exception {}", change.getNewPath(), e.getMessage()); } } }
/** * Remove a {@link DataNode} from the {@link FlowGraph}. The method extracts the nodeId of the * {@link DataNode} from the node config file and uses it to delete the associated {@link DataNode}. * @param change */ private void removeDataNode(DiffEntry change) { if (checkFilePath(change.getOldPath(), NODE_FILE_DEPTH)) { Path nodeFilePath = new Path(this.repositoryDir, change.getOldPath()); Config config = getNodeConfigWithOverrides(ConfigFactory.empty(), nodeFilePath); String nodeId = config.getString(FlowGraphConfigurationKeys.DATA_NODE_ID_KEY); if (!this.flowGraph.deleteDataNode(nodeId)) { log.warn("Could not remove DataNode {} from FlowGraph; skipping", nodeId); } else { log.info("Removed DataNode {} from FlowGraph", nodeId); } } }
public static BlobIdent getNewBlobIdent(DiffEntry diffEntry, String newRev) { BlobIdent blobIdent; if (diffEntry.getChangeType() != ChangeType.DELETE) { blobIdent = new BlobIdent(newRev, diffEntry.getNewPath(), diffEntry.getNewMode().getBits()); } else { blobIdent = new BlobIdent(newRev, null, null); } return blobIdent; }
private DiffEntry findRename(RevCommit parent, RevCommit commit, PathFilter path) throws IOException { if (renameDetector == null) return null; treeWalk.setFilter(TreeFilter.ANY_DIFF); treeWalk.reset(parent.getTree(), commit.getTree()); renameDetector.reset(); renameDetector.addAll(DiffEntry.scan(treeWalk)); for (DiffEntry ent : renameDetector.compute()) { if (isRename(ent) && ent.getNewPath().equals(path.getPath())) return ent; } return null; }
TreeWalk tw = new TreeWalk(repository); tw.setRecursive(true); tw.addTree(CommitUtils.getHead(repository).getTree()); tw.addTree(new FileTreeIterator(repository)); RenameDetector rd = new RenameDetector(repository); rd.addAll(DiffEntry.scan(tw)); List<DiffEntry> lde = rd.compute(tw.getObjectReader(), null); for (DiffEntry de : lde) { if (de.getScore() >= rd.getRenameScore()) { System.out.println("file: " + de.getOldPath() + " copied/moved to: " + de.getNewPath()); } }
switch (entry.getChangeType()) { case ADD: added.add(entry); if (sameType(entry.getOldMode(), entry.getNewMode())) { entries.add(entry); } else { List<DiffEntry> tmp = DiffEntry.breakModify(entry); deleted.add(tmp.get(0)); added.add(tmp.get(1));
private void breakModifies(ContentSource.Pair reader, ProgressMonitor pm) throws IOException, CancelledException { ArrayList<DiffEntry> newEntries = new ArrayList<>(entries.size()); pm.beginTask(JGitText.get().renamesBreakingModifies, entries.size()); for (int i = 0; i < entries.size(); i++) { DiffEntry e = entries.get(i); if (e.getChangeType() == ChangeType.MODIFY) { int score = calculateModifyScore(reader, e); if (score < breakScore) { List<DiffEntry> tmp = DiffEntry.breakModify(e); DiffEntry del = tmp.get(0); del.score = score; deleted.add(del); added.add(tmp.get(1)); } else { newEntries.add(e); } } else { newEntries.add(e); } advanceOrCancel(pm); } entries = newEntries; }