tikhomirov@192: /* tikhomirov@628: * Copyright (c) 2011-2013 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@520: import org.tmatesoft.hg.internal.Lifecycle; tikhomirov@520: import org.tmatesoft.hg.internal.LifecycleBridge; 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@628: import org.tmatesoft.hg.repo.HgRuntimeException; tikhomirov@192: import org.tmatesoft.hg.repo.HgStatusCollector; tikhomirov@432: import org.tmatesoft.hg.repo.HgParentChildMap; 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@520: /*package-local*/ class ChangesetTransformer implements HgChangelog.Inspector, Adaptable { tikhomirov@205: private final HgChangesetHandler handler; tikhomirov@520: private final LifecycleBridge lifecycleBridge; tikhomirov@328: private final Transformation t; tikhomirov@193: private Set branches; tikhomirov@215: private HgCallbackTargetException failure; tikhomirov@192: tikhomirov@195: // repo and delegate can't be null, parent walker can tikhomirov@215: // ps and cs can't be null tikhomirov@432: public ChangesetTransformer(HgRepository hgRepo, HgChangesetHandler delegate, HgParentChildMap 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@520: // lifecycleBridge takes care of progress and cancellation, plus tikhomirov@520: // gives us explicit way to stop iteration (once HgCallbackTargetException) comes. tikhomirov@520: lifecycleBridge = new LifecycleBridge(ps, cs); tikhomirov@192: } tikhomirov@192: tikhomirov@628: public void next(int revisionNumber, Nodeid nodeid, RawChangeset cset) throws HgRuntimeException { 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@520: lifecycleBridge.nextStep(); tikhomirov@423: } catch (HgCallbackTargetException ex) { tikhomirov@423: failure = ex.setRevision(nodeid).setRevisionIndex(revisionNumber); tikhomirov@520: lifecycleBridge.stop(); 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: throw toThrow; tikhomirov@215: } tikhomirov@520: if (lifecycleBridge.isCancelled()) { tikhomirov@520: CancelledException toThrow = lifecycleBridge.getCancelOrigin(); tikhomirov@520: assert toThrow != 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@432: public Transformation(HgStatusCollector statusCollector, HgParentChildMap 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@520: public T getAdapter(Class adapterClass) { tikhomirov@520: if (adapterClass == Lifecycle.class) { tikhomirov@520: return adapterClass.cast(lifecycleBridge); tikhomirov@423: } tikhomirov@520: // just in case there are more adapters in future tikhomirov@520: return Adaptable.Factory.getAdapter(handler, adapterClass, null); tikhomirov@423: } tikhomirov@192: }