# HG changeset patch # User Artem Tikhomirov # Date 1340303278 -7200 # Node ID 1a3c18d57a8e72e3e39e88d2372ee3e2c858eb2b # Parent a0507a9f3da0138392980d5625a98e5e9f994a9a MqManager evolution: same PatchRecord instances, list patch queues, detect active queue diff -r a0507a9f3da0 -r 1a3c18d57a8e cmdline/org/tmatesoft/hg/console/Main.java --- a/cmdline/org/tmatesoft/hg/console/Main.java Wed Jun 20 21:16:21 2012 +0200 +++ b/cmdline/org/tmatesoft/hg/console/Main.java Thu Jun 21 20:27:58 2012 +0200 @@ -139,6 +139,13 @@ for (PatchRecord pr : mqManager.getAppliedPatches()) { System.out.printf("#%-3d %s, known as cset:%s\n", i++, pr.getName(), pr.getRevision().shortNotation()); } + boolean allAppliedAreKnown = mqManager.getAllKnownPatches().containsAll(mqManager.getAppliedPatches()); + System.out.printf("[sanity] allAppliedAreKnown:%b, not yet applied:%d\n", allAppliedAreKnown, mqManager.getQueueSize()); + Assert.assertTrue(allAppliedAreKnown); + + System.out.printf("Queues: %s, active:%s\n", mqManager.getQueueNames(), mqManager.getActiveQueueName()); + Assert.assertTrue(mqManager.getQueueNames().size() > 1); + Assert.assertTrue(mqManager.getActiveQueueName().length() > 0); } diff -r a0507a9f3da0 -r 1a3c18d57a8e src/org/tmatesoft/hg/repo/ext/MqManager.java --- a/src/org/tmatesoft/hg/repo/ext/MqManager.java Wed Jun 20 21:16:21 2012 +0200 +++ b/src/org/tmatesoft/hg/repo/ext/MqManager.java Thu Jun 21 20:27:58 2012 +0200 @@ -20,9 +20,13 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import org.tmatesoft.hg.core.HgInvalidControlFileException; import org.tmatesoft.hg.core.HgInvalidFileException; @@ -44,6 +48,8 @@ private final HgRepository repo; private List applied = Collections.emptyList(); private List allKnown = Collections.emptyList(); + private List queueNames = Collections.emptyList(); + private String activeQueue = "patches"; public MqManager(HgRepository hgRepo) { repo = hgRepo; @@ -53,11 +59,31 @@ * Updates manager with up-to-date state of the mercurial queues. */ public void refresh() throws HgInvalidControlFileException { + applied = allKnown = Collections.emptyList(); + queueNames = Collections.emptyList(); File repoDir = HgInternals.getRepositoryDir(repo); final LogFacility log = HgInternals.getContext(repo).getLog(); final File fileStatus = new File(repoDir, "patches/status"); final File fileSeries = new File(repoDir, "patches/series"); try { + File queues = new File(repoDir, "patches.queues"); + if (queues.isFile()) { + LineReader lr = new LineReader(queues, log).trimLines(true).skipEmpty(true); + lr.read(new SimpleLineCollector(), queueNames = new LinkedList()); + } + File activeQueueFile = new File(repoDir, "patches.queue"); + ArrayList contents = new ArrayList(); + if (activeQueueFile.isFile()) { + new LineReader(activeQueueFile, log).read(new SimpleLineCollector(), contents); + if (contents.isEmpty()) { + log.warn(getClass(), "File %s with active queue name is empty", activeQueueFile.getName()); + activeQueue = "patches"; + } else { + activeQueue = contents.get(0); + } + } else { + activeQueue = "patches"; + } if (fileStatus.isFile()) { new LineReader(fileStatus, log).read(new LineConsumer>() { @@ -75,13 +101,21 @@ }, applied = new LinkedList()); } if (fileSeries.isFile()) { - new LineReader(fileSeries, log).read(new LineConsumer>() { - - public boolean consume(String line, List result) throws IOException { - result.add(new PatchRecord(null, line, Path.create(".hg/patches/" + line))); - return true; + final Map name2patch = new HashMap(); + for (PatchRecord pr : applied) { + name2patch.put(pr.getName(), pr); + } + LinkedList knownPatchNames = new LinkedList(); + new LineReader(fileSeries, log).read(new SimpleLineCollector(), knownPatchNames); + // XXX read other queues? + allKnown = new ArrayList(knownPatchNames.size()); + for (String name : knownPatchNames) { + PatchRecord pr = name2patch.get(name); + if (pr == null) { + pr = new PatchRecord(null, name, Path.create(".hg/patches/" + name)); } - }, allKnown = new LinkedList()); + allKnown.add(pr); + } } } catch (HgInvalidFileException ex) { HgInvalidControlFileException th = new HgInvalidControlFileException(ex.getMessage(), ex.getCause(), ex.getFile()); @@ -89,9 +123,26 @@ throw th; } } + + static class SimpleLineCollector implements LineConsumer> { + + public boolean consume(String line, Collection result) throws IOException { + result.add(line); + return true; + } + } + + /** + * Number of patches not yet applied + * @return positive value when there are + */ + public int getQueueSize() { + return getAllKnownPatches().size() - getAppliedPatches().size(); + } /** * Subset of the patches from the queue that were already applied to the repository + *

Analog of 'hg qapplied' * *

Clients shall call {@link #refresh()} prior to first use * @return collection of records in no particular order, may be empty if none applied @@ -110,10 +161,30 @@ return Collections.unmodifiableList(allKnown); } + /** + * Name of the patch queue hg qqueue --active which is active now. + * @return patch queue name + */ + public String getActiveQueueName() { + return activeQueue; + } + + /** + * Patch queues known in the repository, hg qqueue -l analog. + * There's at least one patch queue (default one names 'patches'). Only one patch queue at a time is active. + * + * @return names of patch queues + */ + public List getQueueNames() { + return Collections.unmodifiableList(queueNames); + } + public class PatchRecord { private final Nodeid nodeid; private final String name; private final Path location; + + // hashCode/equals might be useful if cons becomes public PatchRecord(Nodeid revision, String name, Path diffLocation) { nodeid = revision; @@ -162,11 +233,41 @@ private final File file; private final LogFacility log; + private boolean trimLines = true; + private boolean skipEmpty = true; + private String ignoreThatStars = null; LineReader(File f, LogFacility logFacility) { file = f; log = logFacility; } + + /** + * default: true + * false to return line as is + */ + LineReader trimLines(boolean trim) { + trimLines = trim; + return this; + } + + /** + * default: true + * false to pass empty lines to consumer + */ + LineReader skipEmpty(boolean skip) { + skipEmpty = skip; + return this; + } + + /** + * default: doesn't skip any line. + * set e.g. to "#" or "//" to skip lines that start with such prefix + */ + LineReader ignoreLineComments(String lineStart) { + ignoreThatStars = lineStart; + return this; + } void read(LineConsumer consumer, T paramObj) throws HgInvalidFileException { BufferedReader statusFileReader = null; @@ -176,8 +277,13 @@ String line; boolean ok = true; while (ok && (line = statusFileReader.readLine()) != null) { - line = line.trim(); - if (line.length() > 0) { + if (trimLines) { + line = line.trim(); + } + if (ignoreThatStars != null && line.startsWith(ignoreThatStars)) { + continue; + } + if (!skipEmpty || line.length() > 0) { ok = consumer.consume(line, paramObj); } }