tikhomirov@192: /* tikhomirov@418: * Copyright (c) 2011-2012 TMate Software Ltd tikhomirov@192: * tikhomirov@192: * This program is free software; you can redistribute it and/or modify tikhomirov@192: * it under the terms of the GNU General Public License as published by tikhomirov@192: * the Free Software Foundation; version 2 of the License. tikhomirov@192: * tikhomirov@192: * This program is distributed in the hope that it will be useful, tikhomirov@192: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@192: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@192: * GNU General Public License for more details. tikhomirov@192: * tikhomirov@192: * For information on how to redistribute this software under tikhomirov@192: * the terms of a license other than GNU General Public License tikhomirov@192: * contact TMate Software at support@hg4j.com tikhomirov@192: */ tikhomirov@192: package org.tmatesoft.hg.core; tikhomirov@192: tikhomirov@193: import java.util.Set; tikhomirov@193: tikhomirov@431: import org.tmatesoft.hg.internal.PathPool; tikhomirov@192: import org.tmatesoft.hg.repo.HgChangelog; tikhomirov@205: import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; tikhomirov@192: import org.tmatesoft.hg.repo.HgRepository; tikhomirov@192: import org.tmatesoft.hg.repo.HgStatusCollector; tikhomirov@423: import org.tmatesoft.hg.util.Adaptable; tikhomirov@215: import org.tmatesoft.hg.util.CancelSupport; tikhomirov@215: import org.tmatesoft.hg.util.CancelledException; tikhomirov@192: import org.tmatesoft.hg.util.PathRewrite; tikhomirov@215: import org.tmatesoft.hg.util.ProgressSupport; tikhomirov@192: tikhomirov@192: /** tikhomirov@192: * Bridges {@link HgChangelog.RawChangeset} with high-level {@link HgChangeset} API tikhomirov@418: * TODO post-1.0 Move to .internal once access to package-local HgChangeset cons is resolved. For 1.0, enough it's package-local tikhomirov@192: * tikhomirov@192: * @author Artem Tikhomirov tikhomirov@192: * @author TMate Software Ltd. tikhomirov@192: */ tikhomirov@423: /*package-local*/ class ChangesetTransformer implements HgChangelog.Inspector, Adaptable, CancelSupport { tikhomirov@205: private final HgChangesetHandler handler; tikhomirov@215: private final ProgressSupport progressHelper; tikhomirov@215: private final CancelSupport cancelHelper; tikhomirov@328: private final Transformation t; tikhomirov@193: private Set branches; tikhomirov@215: private HgCallbackTargetException failure; tikhomirov@215: private CancelledException cancellation; tikhomirov@192: tikhomirov@195: // repo and delegate can't be null, parent walker can tikhomirov@215: // ps and cs can't be null tikhomirov@215: public ChangesetTransformer(HgRepository hgRepo, HgChangesetHandler delegate, HgChangelog.ParentWalker pw, ProgressSupport ps, CancelSupport cs) { tikhomirov@192: if (hgRepo == null || delegate == null) { tikhomirov@192: throw new IllegalArgumentException(); tikhomirov@192: } tikhomirov@215: if (ps == null || cs == null) { tikhomirov@215: throw new IllegalArgumentException(); tikhomirov@215: } tikhomirov@192: HgStatusCollector statusCollector = new HgStatusCollector(hgRepo); tikhomirov@328: t = new Transformation(statusCollector, pw); tikhomirov@192: handler = delegate; tikhomirov@423: // we let HgChangelog#range deal with progress (pipe through getAdapter) tikhomirov@423: // but use own cancellation (which involves CallbackTargetException as well, and preserves original cancellation tikhomirov@423: // exception in case clients care) tikhomirov@215: cancelHelper = cs; tikhomirov@215: progressHelper = ps; tikhomirov@192: } tikhomirov@192: tikhomirov@192: public void next(int revisionNumber, Nodeid nodeid, RawChangeset cset) { tikhomirov@193: if (branches != null && !branches.contains(cset.branch())) { tikhomirov@193: return; tikhomirov@193: } tikhomirov@193: tikhomirov@328: HgChangeset changeset = t.handle(revisionNumber, nodeid, cset); tikhomirov@215: try { tikhomirov@427: handler.cset(changeset); tikhomirov@215: cancelHelper.checkCancelled(); tikhomirov@423: } catch (HgCallbackTargetException ex) { tikhomirov@423: failure = ex.setRevision(nodeid).setRevisionIndex(revisionNumber); tikhomirov@215: } catch (CancelledException ex) { tikhomirov@215: cancellation = ex; tikhomirov@215: } tikhomirov@215: } tikhomirov@215: tikhomirov@215: public void checkFailure() throws HgCallbackTargetException, CancelledException { tikhomirov@215: if (failure != null) { tikhomirov@215: HgCallbackTargetException toThrow = failure; tikhomirov@215: failure = null; // just in (otherwise unexpected) case this instance would get reused tikhomirov@215: throw toThrow; tikhomirov@215: } tikhomirov@215: if (cancellation != null) { tikhomirov@215: CancelledException toThrow = cancellation; tikhomirov@215: cancellation = null; tikhomirov@215: throw toThrow; tikhomirov@215: } tikhomirov@192: } tikhomirov@193: tikhomirov@193: public void limitBranches(Set branches) { tikhomirov@193: this.branches = branches; tikhomirov@193: } tikhomirov@328: tikhomirov@328: // part relevant to RawChangeset->HgChangeset transformation tikhomirov@328: static class Transformation { tikhomirov@328: private final HgChangeset changeset; tikhomirov@328: tikhomirov@328: public Transformation(HgStatusCollector statusCollector, HgChangelog.ParentWalker pw) { tikhomirov@328: // files listed in a changeset don't need their names to be rewritten (they are normalized already) tikhomirov@431: // pp serves as a cache for all filenames encountered and as a source for Path listed in the changeset tikhomirov@328: PathPool pp = new PathPool(new PathRewrite.Empty()); tikhomirov@328: statusCollector.setPathPool(pp); tikhomirov@328: changeset = new HgChangeset(statusCollector, pp); tikhomirov@328: changeset.setParentHelper(pw); tikhomirov@328: } tikhomirov@403: tikhomirov@418: /** tikhomirov@418: * Callers shall not assume they get new HgChangeset instance each time, implementation may reuse instances. tikhomirov@418: * @return hi-level changeset description tikhomirov@418: */ tikhomirov@328: HgChangeset handle(int revisionNumber, Nodeid nodeid, RawChangeset cset) { tikhomirov@328: changeset.init(revisionNumber, nodeid, cset); tikhomirov@328: return changeset; tikhomirov@328: } tikhomirov@328: } tikhomirov@423: tikhomirov@423: public void checkCancelled() throws CancelledException { tikhomirov@423: if (failure != null || cancellation != null) { tikhomirov@423: // stop HgChangelog.Iterator. Our exception is for the purposes of cancellation only, tikhomirov@423: // the one we have stored (this.cancellation) is for user tikhomirov@423: throw new CancelledException(); tikhomirov@423: } tikhomirov@423: } tikhomirov@423: tikhomirov@423: public T getAdapter(Class adapterClass) { tikhomirov@423: if (adapterClass == ProgressSupport.class) { tikhomirov@423: return adapterClass.cast(progressHelper); tikhomirov@423: } tikhomirov@423: return null; tikhomirov@423: } tikhomirov@192: }