Mercurial > jhg
comparison src/org/tmatesoft/hg/repo/HgDataFile.java @ 305:ae8d116f4ee2
Experimental code to build file history
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Thu, 22 Sep 2011 03:57:38 +0200 |
| parents | 650b45d290b1 |
| children | 971baa95fb07 |
comparison
equal
deleted
inserted
replaced
| 304:85b8efde5586 | 305:ae8d116f4ee2 |
|---|---|
| 26 import java.nio.ByteBuffer; | 26 import java.nio.ByteBuffer; |
| 27 import java.nio.channels.FileChannel; | 27 import java.nio.channels.FileChannel; |
| 28 import java.util.ArrayList; | 28 import java.util.ArrayList; |
| 29 import java.util.Arrays; | 29 import java.util.Arrays; |
| 30 import java.util.Collection; | 30 import java.util.Collection; |
| 31 import java.util.Collections; | |
| 32 import java.util.List; | |
| 33 import java.util.NoSuchElementException; | |
| 31 | 34 |
| 32 import org.tmatesoft.hg.core.HgDataStreamException; | 35 import org.tmatesoft.hg.core.HgDataStreamException; |
| 33 import org.tmatesoft.hg.core.HgException; | 36 import org.tmatesoft.hg.core.HgException; |
| 34 import org.tmatesoft.hg.core.Nodeid; | 37 import org.tmatesoft.hg.core.Nodeid; |
| 35 import org.tmatesoft.hg.internal.DataAccess; | 38 import org.tmatesoft.hg.internal.DataAccess; |
| 39 import org.tmatesoft.hg.internal.Experimental; | |
| 36 import org.tmatesoft.hg.internal.FilterByteChannel; | 40 import org.tmatesoft.hg.internal.FilterByteChannel; |
| 37 import org.tmatesoft.hg.internal.FilterDataAccess; | 41 import org.tmatesoft.hg.internal.FilterDataAccess; |
| 38 import org.tmatesoft.hg.internal.IntMap; | 42 import org.tmatesoft.hg.internal.IntMap; |
| 39 import org.tmatesoft.hg.internal.RevlogStream; | 43 import org.tmatesoft.hg.internal.RevlogStream; |
| 44 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; | |
| 40 import org.tmatesoft.hg.util.ByteChannel; | 45 import org.tmatesoft.hg.util.ByteChannel; |
| 41 import org.tmatesoft.hg.util.CancelSupport; | 46 import org.tmatesoft.hg.util.CancelSupport; |
| 42 import org.tmatesoft.hg.util.CancelledException; | 47 import org.tmatesoft.hg.util.CancelledException; |
| 48 import org.tmatesoft.hg.util.Pair; | |
| 43 import org.tmatesoft.hg.util.Path; | 49 import org.tmatesoft.hg.util.Path; |
| 44 import org.tmatesoft.hg.util.ProgressSupport; | 50 import org.tmatesoft.hg.util.ProgressSupport; |
| 45 | 51 |
| 46 | 52 |
| 47 | 53 |
| 221 throw new HgDataStreamException(getPath(), ex); | 227 throw new HgDataStreamException(getPath(), ex); |
| 222 } catch (HgException ex) { | 228 } catch (HgException ex) { |
| 223 // shall not happen, unless we changed ContentPipe or its subclass | 229 // shall not happen, unless we changed ContentPipe or its subclass |
| 224 throw new HgDataStreamException(getPath(), ex.getClass().getName(), ex); | 230 throw new HgDataStreamException(getPath(), ex.getClass().getName(), ex); |
| 225 } | 231 } |
| 232 } | |
| 233 | |
| 234 @Experimental(reason="Investigate approaches to build complete file history log") | |
| 235 public interface HistoryWalker { | |
| 236 void next(); | |
| 237 boolean hasNext(); | |
| 238 Nodeid changesetRevision(); | |
| 239 RawChangeset changeset(); | |
| 240 boolean isFork(); | |
| 241 boolean isJoin(); | |
| 242 Pair<Nodeid, Nodeid> parentChangesets(); | |
| 243 Collection<Nodeid> childChangesets(); | |
| 244 } | |
| 245 | |
| 246 public HistoryWalker history() { | |
| 247 final boolean[] needsSorting = { false }; | |
| 248 class HistoryNode { | |
| 249 int changeset; | |
| 250 Nodeid cset; | |
| 251 HistoryNode parent1, parent2; | |
| 252 List<HistoryNode> children; | |
| 253 | |
| 254 public HistoryNode(int cs, HistoryNode p1, HistoryNode p2) { | |
| 255 changeset = cs; | |
| 256 parent1 = p1; | |
| 257 parent2 = p2; | |
| 258 if (p1 != null) { | |
| 259 p1.addChild(this); | |
| 260 } | |
| 261 if (p2 != null) { | |
| 262 p2.addChild(this); | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 public Nodeid changesetRevision() { | |
| 267 if (cset == null) { | |
| 268 cset = getRepo().getChangelog().getRevision(changeset); | |
| 269 } | |
| 270 return cset; | |
| 271 } | |
| 272 | |
| 273 public void addChild(HistoryNode child) { | |
| 274 if (children == null) { | |
| 275 children = new ArrayList<HistoryNode>(2); | |
| 276 } | |
| 277 children.add(child); | |
| 278 } | |
| 279 } | |
| 280 final HistoryNode[] completeHistory = new HistoryNode[getRevisionCount()]; | |
| 281 final int[] commitRevisions = new int[completeHistory.length]; | |
| 282 RevlogStream.Inspector insp = new RevlogStream.Inspector() { | |
| 283 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { | |
| 284 if (revisionNumber > 0) { | |
| 285 if (commitRevisions[revisionNumber-1] > linkRevision) { | |
| 286 needsSorting[0] = true; | |
| 287 } | |
| 288 } | |
| 289 HistoryNode p1 = null, p2 = null; | |
| 290 if (parent1Revision != -1) { | |
| 291 p1 = completeHistory[parent1Revision]; | |
| 292 } | |
| 293 if (parent2Revision != -1) { | |
| 294 p2 = completeHistory[parent2Revision]; | |
| 295 } | |
| 296 completeHistory[revisionNumber] = new HistoryNode(linkRevision, p1, p2); | |
| 297 } | |
| 298 }; | |
| 299 content.iterate(0, getLastRevision(), false, insp); | |
| 300 // XXX may read changeset revisions at once (to avoid numerous changelog.getRevision reads) | |
| 301 // but perhaps just nodeids, not RawChangeset (changelog.iterate(data=false) | |
| 302 // XXX sort completeHistory according to changeset numbers? | |
| 303 return new HistoryWalker() { | |
| 304 private int index = -1; | |
| 305 | |
| 306 public void next() { | |
| 307 if (!hasNext()) { | |
| 308 throw new NoSuchElementException(); | |
| 309 } | |
| 310 index++; | |
| 311 } | |
| 312 | |
| 313 public boolean hasNext() { | |
| 314 return index+1 < completeHistory.length; | |
| 315 } | |
| 316 | |
| 317 public Pair<Nodeid, Nodeid> parentChangesets() { | |
| 318 HistoryNode p; | |
| 319 Nodeid p1, p2; | |
| 320 if ((p = completeHistory[index].parent1) != null) { | |
| 321 p1 = p.changesetRevision(); | |
| 322 } else { | |
| 323 p1 = Nodeid.NULL; | |
| 324 } | |
| 325 if ((p = completeHistory[index].parent2) != null) { | |
| 326 p2 = p.changesetRevision(); | |
| 327 } else { | |
| 328 p2 = Nodeid.NULL; | |
| 329 } | |
| 330 return new Pair<Nodeid, Nodeid>(p1, p2); | |
| 331 } | |
| 332 | |
| 333 public boolean isJoin() { | |
| 334 return completeHistory[index].parent1 != null && completeHistory[index].parent2 != null; | |
| 335 } | |
| 336 | |
| 337 public boolean isFork() { | |
| 338 HistoryNode n = completeHistory[index]; | |
| 339 return n.children != null && n.children.size() > 1; | |
| 340 } | |
| 341 | |
| 342 public Collection<Nodeid> childChangesets() { | |
| 343 HistoryNode n = completeHistory[index]; | |
| 344 if (n.children == null) { | |
| 345 return Collections.emptyList(); | |
| 346 } | |
| 347 ArrayList<Nodeid> rv = new ArrayList<Nodeid>(n.children.size()); | |
| 348 for (HistoryNode hn : n.children) { | |
| 349 rv.add(hn.changesetRevision()); | |
| 350 } | |
| 351 return rv; | |
| 352 } | |
| 353 | |
| 354 public Nodeid changesetRevision() { | |
| 355 return completeHistory[index].changesetRevision(); | |
| 356 } | |
| 357 | |
| 358 public RawChangeset changeset() { | |
| 359 | |
| 360 return null; | |
| 361 } | |
| 362 }; | |
| 226 } | 363 } |
| 227 | 364 |
| 228 public void history(HgChangelog.Inspector inspector) { | 365 public void history(HgChangelog.Inspector inspector) { |
| 229 history(0, getLastRevision(), inspector); | 366 history(0, getLastRevision(), inspector); |
| 230 } | 367 } |
