comparison src/org/tmatesoft/hg/repo/HgDataFile.java @ 603:707b5c7c6fa4

Refactor HgBlameFacility: relevant action methods moved to proper home (HgDataFile), as facility doesn't provide anything but packaging of relevant methods/interfaces
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Mon, 06 May 2013 18:29:57 +0200
parents e3717fc7d26f
children e1b29756f901
comparison
equal deleted inserted replaced
602:e3717fc7d26f 603:707b5c7c6fa4
1 /* 1 /*
2 * Copyright (c) 2010-2012 TMate Software Ltd 2 * Copyright (c) 2010-2013 TMate Software Ltd
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by 5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License. 6 * the Free Software Foundation; version 2 of the License.
7 * 7 *
14 * the terms of a license other than GNU General Public License 14 * the terms of a license other than GNU General Public License
15 * contact TMate Software at support@hg4j.com 15 * contact TMate Software at support@hg4j.com
16 */ 16 */
17 package org.tmatesoft.hg.repo; 17 package org.tmatesoft.hg.repo;
18 18
19 import static org.tmatesoft.hg.core.HgIterateDirection.OldToNew;
19 import static org.tmatesoft.hg.repo.HgInternals.wrongRevisionIndex; 20 import static org.tmatesoft.hg.repo.HgInternals.wrongRevisionIndex;
20 import static org.tmatesoft.hg.repo.HgRepository.*; 21 import static org.tmatesoft.hg.repo.HgRepository.*;
21 import static org.tmatesoft.hg.util.LogFacility.Severity.Info; 22 import static org.tmatesoft.hg.util.LogFacility.Severity.Info;
22 import static org.tmatesoft.hg.util.LogFacility.Severity.Warn; 23 import static org.tmatesoft.hg.util.LogFacility.Severity.Warn;
23 24
26 import java.io.IOException; 27 import java.io.IOException;
27 import java.nio.ByteBuffer; 28 import java.nio.ByteBuffer;
28 import java.nio.channels.FileChannel; 29 import java.nio.channels.FileChannel;
29 import java.util.Arrays; 30 import java.util.Arrays;
30 31
32 import org.tmatesoft.hg.core.HgCallbackTargetException;
31 import org.tmatesoft.hg.core.HgChangesetFileSneaker; 33 import org.tmatesoft.hg.core.HgChangesetFileSneaker;
34 import org.tmatesoft.hg.core.HgIterateDirection;
32 import org.tmatesoft.hg.core.Nodeid; 35 import org.tmatesoft.hg.core.Nodeid;
36 import org.tmatesoft.hg.internal.BlameHelper;
33 import org.tmatesoft.hg.internal.DataAccess; 37 import org.tmatesoft.hg.internal.DataAccess;
38 import org.tmatesoft.hg.internal.FileHistory;
39 import org.tmatesoft.hg.internal.FileRevisionHistoryChunk;
34 import org.tmatesoft.hg.internal.FilterByteChannel; 40 import org.tmatesoft.hg.internal.FilterByteChannel;
35 import org.tmatesoft.hg.internal.FilterDataAccess; 41 import org.tmatesoft.hg.internal.FilterDataAccess;
36 import org.tmatesoft.hg.internal.Internals; 42 import org.tmatesoft.hg.internal.Internals;
37 import org.tmatesoft.hg.internal.Metadata; 43 import org.tmatesoft.hg.internal.Metadata;
38 import org.tmatesoft.hg.internal.RevlogStream; 44 import org.tmatesoft.hg.internal.RevlogStream;
45 import org.tmatesoft.hg.repo.HgBlameInspector;
39 import org.tmatesoft.hg.util.ByteChannel; 46 import org.tmatesoft.hg.util.ByteChannel;
40 import org.tmatesoft.hg.util.CancelSupport; 47 import org.tmatesoft.hg.util.CancelSupport;
41 import org.tmatesoft.hg.util.CancelledException; 48 import org.tmatesoft.hg.util.CancelledException;
42 import org.tmatesoft.hg.util.LogFacility; 49 import org.tmatesoft.hg.util.LogFacility;
43 import org.tmatesoft.hg.util.Pair; 50 import org.tmatesoft.hg.util.Pair;
426 public HgManifest.Flags getFlags(int fileRevisionIndex) throws HgRuntimeException { 433 public HgManifest.Flags getFlags(int fileRevisionIndex) throws HgRuntimeException {
427 int changesetRevIndex = getChangesetRevisionIndex(fileRevisionIndex); 434 int changesetRevIndex = getChangesetRevisionIndex(fileRevisionIndex);
428 return getRepo().getManifest().getFileFlags(changesetRevIndex, getPath()); 435 return getRepo().getManifest().getFileFlags(changesetRevIndex, getPath());
429 } 436 }
430 437
438 /**
439 * mimic 'hg diff -r clogRevIndex1 -r clogRevIndex2'
440 */
441 public void diff(int clogRevIndex1, int clogRevIndex2, HgBlameInspector insp) throws HgCallbackTargetException {
442 // FIXME clogRevIndex1 and clogRevIndex2 may point to different files, need to decide whether to throw an exception
443 // or to attempt to look up correct file node (tricky)
444 int fileRevIndex1 = fileRevIndex(this, clogRevIndex1);
445 int fileRevIndex2 = fileRevIndex(this, clogRevIndex2);
446 BlameHelper bh = new BlameHelper(insp, 5);
447 bh.useFileUpTo(this, clogRevIndex2);
448 bh.diff(fileRevIndex1, clogRevIndex1, fileRevIndex2, clogRevIndex2);
449 }
450
451 /**
452 * Walk file history up/down to revision at given changeset and report changes for each revision
453 */
454 public void annotate(int changelogRevisionIndex, HgBlameInspector insp, HgIterateDirection iterateOrder) throws HgCallbackTargetException {
455 annotate(0, changelogRevisionIndex, insp, iterateOrder);
456 }
457
458 /**
459 * Walk file history range and report changes for each revision
460 */
461 public void annotate(int changelogRevIndexStart, int changelogRevIndexEnd, HgBlameInspector insp, HgIterateDirection iterateOrder) throws HgCallbackTargetException {
462 if (wrongRevisionIndex(changelogRevIndexStart) || wrongRevisionIndex(changelogRevIndexEnd)) {
463 throw new IllegalArgumentException();
464 }
465 // Note, changelogRevIndexEnd may be TIP, while the code below doesn't tolerate constants
466 //
467 int lastRevision = getRepo().getChangelog().getLastRevision();
468 if (changelogRevIndexEnd == TIP) {
469 changelogRevIndexEnd = lastRevision;
470 }
471 HgInternals.checkRevlogRange(changelogRevIndexStart, changelogRevIndexEnd, lastRevision);
472 if (!exists()) {
473 return;
474 }
475 FileHistory fileHistory = new FileHistory(this, changelogRevIndexStart, changelogRevIndexEnd);
476 fileHistory.build();
477 BlameHelper bh = new BlameHelper(insp, 10);
478 for (FileRevisionHistoryChunk fhc : fileHistory.iterate(OldToNew)) {
479 // iteration order is not important here
480 bh.useFileUpTo(fhc.getFile(), fhc.getEndChangeset());
481 }
482 int[] fileClogParentRevs = new int[2];
483 int[] fileParentRevs = new int[2];
484 for (FileRevisionHistoryChunk fhc : fileHistory.iterate(iterateOrder)) {
485 for (int fri : fhc.fileRevisions(iterateOrder)) {
486 int clogRevIndex = fhc.changeset(fri);
487 // the way we built fileHistory ensures we won't walk past [changelogRevIndexStart..changelogRevIndexEnd]
488 assert clogRevIndex >= changelogRevIndexStart;
489 assert clogRevIndex <= changelogRevIndexEnd;
490 fhc.fillFileParents(fri, fileParentRevs);
491 fhc.fillCsetParents(fri, fileClogParentRevs);
492 bh.annotateChange(fri, clogRevIndex, fileParentRevs, fileClogParentRevs);
493 }
494 }
495 }
496
497 /**
498 * Annotates changes of the file against its parent(s).
499 * Unlike {@link #annotate(HgDataFile, int, Inspector, HgIterateDirection)}, doesn't
500 * walk file history, looks at the specified revision only. Handles both parents (if merge revision).
501 */
502 public void annotateSingleRevision(int changelogRevisionIndex, HgBlameInspector insp) throws HgCallbackTargetException {
503 // TODO detect if file is text/binary (e.g. looking for chars < ' ' and not \t\r\n\f
504 int fileRevIndex = fileRevIndex(this, changelogRevisionIndex);
505 int[] fileRevParents = new int[2];
506 parents(fileRevIndex, fileRevParents, null, null);
507 if (changelogRevisionIndex == TIP) {
508 changelogRevisionIndex = getChangesetRevisionIndex(fileRevIndex);
509 }
510 BlameHelper bh = new BlameHelper(insp, 5);
511 bh.useFileUpTo(this, changelogRevisionIndex);
512 int[] fileClogParentRevs = new int[2];
513 fileClogParentRevs[0] = fileRevParents[0] == NO_REVISION ? NO_REVISION : getChangesetRevisionIndex(fileRevParents[0]);
514 fileClogParentRevs[1] = fileRevParents[1] == NO_REVISION ? NO_REVISION : getChangesetRevisionIndex(fileRevParents[1]);
515 bh.annotateChange(fileRevIndex, changelogRevisionIndex, fileRevParents, fileClogParentRevs);
516 }
517
431 @Override 518 @Override
432 public String toString() { 519 public String toString() {
433 StringBuilder sb = new StringBuilder(getClass().getSimpleName()); 520 StringBuilder sb = new StringBuilder(getClass().getSimpleName());
434 sb.append('('); 521 sb.append('(');
435 sb.append(getPath()); 522 sb.append(getPath());
443 } 530 }
444 // use MetadataInspector without delegate to process metadata only 531 // use MetadataInspector without delegate to process metadata only
445 RevlogStream.Inspector insp = new MetadataInspector(metadata, null); 532 RevlogStream.Inspector insp = new MetadataInspector(metadata, null);
446 super.content.iterate(localRev, localRev, true, insp); 533 super.content.iterate(localRev, localRev, true, insp);
447 } 534 }
535
536
537 private static int fileRevIndex(HgDataFile df, int csetRevIndex) {
538 Nodeid fileRev = df.getRepo().getManifest().getFileRevision(csetRevIndex, df.getPath());
539 return df.getRevisionIndex(fileRev);
540 }
541
448 542
449 private static class MetadataInspector extends ErrorHandlingInspector implements RevlogStream.Inspector { 543 private static class MetadataInspector extends ErrorHandlingInspector implements RevlogStream.Inspector {
450 private final Metadata metadata; 544 private final Metadata metadata;
451 private final RevlogStream.Inspector delegate; 545 private final RevlogStream.Inspector delegate;
452 546