Mercurial > jhg
comparison src/org/tmatesoft/hg/repo/ext/MqManager.java @ 464:1a3c18d57a8e smartgit3
MqManager evolution: same PatchRecord instances, list patch queues, detect active queue
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Thu, 21 Jun 2012 20:27:58 +0200 |
| parents | a0507a9f3da0 |
| children | 2078692eeb58 |
comparison
equal
deleted
inserted
replaced
| 463:a0507a9f3da0 | 464:1a3c18d57a8e |
|---|---|
| 18 | 18 |
| 19 import java.io.BufferedReader; | 19 import java.io.BufferedReader; |
| 20 import java.io.File; | 20 import java.io.File; |
| 21 import java.io.FileReader; | 21 import java.io.FileReader; |
| 22 import java.io.IOException; | 22 import java.io.IOException; |
| 23 import java.util.ArrayList; | |
| 24 import java.util.Collection; | |
| 23 import java.util.Collections; | 25 import java.util.Collections; |
| 26 import java.util.HashMap; | |
| 24 import java.util.LinkedList; | 27 import java.util.LinkedList; |
| 25 import java.util.List; | 28 import java.util.List; |
| 29 import java.util.Map; | |
| 26 | 30 |
| 27 import org.tmatesoft.hg.core.HgInvalidControlFileException; | 31 import org.tmatesoft.hg.core.HgInvalidControlFileException; |
| 28 import org.tmatesoft.hg.core.HgInvalidFileException; | 32 import org.tmatesoft.hg.core.HgInvalidFileException; |
| 29 import org.tmatesoft.hg.core.Nodeid; | 33 import org.tmatesoft.hg.core.Nodeid; |
| 30 import org.tmatesoft.hg.repo.HgInternals; | 34 import org.tmatesoft.hg.repo.HgInternals; |
| 42 public class MqManager { | 46 public class MqManager { |
| 43 | 47 |
| 44 private final HgRepository repo; | 48 private final HgRepository repo; |
| 45 private List<PatchRecord> applied = Collections.emptyList(); | 49 private List<PatchRecord> applied = Collections.emptyList(); |
| 46 private List<PatchRecord> allKnown = Collections.emptyList(); | 50 private List<PatchRecord> allKnown = Collections.emptyList(); |
| 51 private List<String> queueNames = Collections.emptyList(); | |
| 52 private String activeQueue = "patches"; | |
| 47 | 53 |
| 48 public MqManager(HgRepository hgRepo) { | 54 public MqManager(HgRepository hgRepo) { |
| 49 repo = hgRepo; | 55 repo = hgRepo; |
| 50 } | 56 } |
| 51 | 57 |
| 52 /** | 58 /** |
| 53 * Updates manager with up-to-date state of the mercurial queues. | 59 * Updates manager with up-to-date state of the mercurial queues. |
| 54 */ | 60 */ |
| 55 public void refresh() throws HgInvalidControlFileException { | 61 public void refresh() throws HgInvalidControlFileException { |
| 62 applied = allKnown = Collections.emptyList(); | |
| 63 queueNames = Collections.emptyList(); | |
| 56 File repoDir = HgInternals.getRepositoryDir(repo); | 64 File repoDir = HgInternals.getRepositoryDir(repo); |
| 57 final LogFacility log = HgInternals.getContext(repo).getLog(); | 65 final LogFacility log = HgInternals.getContext(repo).getLog(); |
| 58 final File fileStatus = new File(repoDir, "patches/status"); | 66 final File fileStatus = new File(repoDir, "patches/status"); |
| 59 final File fileSeries = new File(repoDir, "patches/series"); | 67 final File fileSeries = new File(repoDir, "patches/series"); |
| 60 try { | 68 try { |
| 69 File queues = new File(repoDir, "patches.queues"); | |
| 70 if (queues.isFile()) { | |
| 71 LineReader lr = new LineReader(queues, log).trimLines(true).skipEmpty(true); | |
| 72 lr.read(new SimpleLineCollector(), queueNames = new LinkedList<String>()); | |
| 73 } | |
| 74 File activeQueueFile = new File(repoDir, "patches.queue"); | |
| 75 ArrayList<String> contents = new ArrayList<String>(); | |
| 76 if (activeQueueFile.isFile()) { | |
| 77 new LineReader(activeQueueFile, log).read(new SimpleLineCollector(), contents); | |
| 78 if (contents.isEmpty()) { | |
| 79 log.warn(getClass(), "File %s with active queue name is empty", activeQueueFile.getName()); | |
| 80 activeQueue = "patches"; | |
| 81 } else { | |
| 82 activeQueue = contents.get(0); | |
| 83 } | |
| 84 } else { | |
| 85 activeQueue = "patches"; | |
| 86 } | |
| 61 if (fileStatus.isFile()) { | 87 if (fileStatus.isFile()) { |
| 62 new LineReader(fileStatus, log).read(new LineConsumer<List<PatchRecord>>() { | 88 new LineReader(fileStatus, log).read(new LineConsumer<List<PatchRecord>>() { |
| 63 | 89 |
| 64 public boolean consume(String line, List<PatchRecord> result) throws IOException { | 90 public boolean consume(String line, List<PatchRecord> result) throws IOException { |
| 65 int sep = line.indexOf(':'); | 91 int sep = line.indexOf(':'); |
| 73 return true; | 99 return true; |
| 74 } | 100 } |
| 75 }, applied = new LinkedList<PatchRecord>()); | 101 }, applied = new LinkedList<PatchRecord>()); |
| 76 } | 102 } |
| 77 if (fileSeries.isFile()) { | 103 if (fileSeries.isFile()) { |
| 78 new LineReader(fileSeries, log).read(new LineConsumer<List<PatchRecord>>() { | 104 final Map<String,PatchRecord> name2patch = new HashMap<String, PatchRecord>(); |
| 79 | 105 for (PatchRecord pr : applied) { |
| 80 public boolean consume(String line, List<PatchRecord> result) throws IOException { | 106 name2patch.put(pr.getName(), pr); |
| 81 result.add(new PatchRecord(null, line, Path.create(".hg/patches/" + line))); | 107 } |
| 82 return true; | 108 LinkedList<String> knownPatchNames = new LinkedList<String>(); |
| 83 } | 109 new LineReader(fileSeries, log).read(new SimpleLineCollector(), knownPatchNames); |
| 84 }, allKnown = new LinkedList<PatchRecord>()); | 110 // XXX read other queues? |
| 111 allKnown = new ArrayList<PatchRecord>(knownPatchNames.size()); | |
| 112 for (String name : knownPatchNames) { | |
| 113 PatchRecord pr = name2patch.get(name); | |
| 114 if (pr == null) { | |
| 115 pr = new PatchRecord(null, name, Path.create(".hg/patches/" + name)); | |
| 116 } | |
| 117 allKnown.add(pr); | |
| 118 } | |
| 85 } | 119 } |
| 86 } catch (HgInvalidFileException ex) { | 120 } catch (HgInvalidFileException ex) { |
| 87 HgInvalidControlFileException th = new HgInvalidControlFileException(ex.getMessage(), ex.getCause(), ex.getFile()); | 121 HgInvalidControlFileException th = new HgInvalidControlFileException(ex.getMessage(), ex.getCause(), ex.getFile()); |
| 88 th.setStackTrace(ex.getStackTrace()); | 122 th.setStackTrace(ex.getStackTrace()); |
| 89 throw th; | 123 throw th; |
| 90 } | 124 } |
| 91 } | 125 } |
| 126 | |
| 127 static class SimpleLineCollector implements LineConsumer<Collection<String>> { | |
| 128 | |
| 129 public boolean consume(String line, Collection<String> result) throws IOException { | |
| 130 result.add(line); | |
| 131 return true; | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 /** | |
| 136 * Number of patches not yet applied | |
| 137 * @return positive value when there are | |
| 138 */ | |
| 139 public int getQueueSize() { | |
| 140 return getAllKnownPatches().size() - getAppliedPatches().size(); | |
| 141 } | |
| 92 | 142 |
| 93 /** | 143 /** |
| 94 * Subset of the patches from the queue that were already applied to the repository | 144 * Subset of the patches from the queue that were already applied to the repository |
| 145 * <p>Analog of 'hg qapplied' | |
| 95 * | 146 * |
| 96 * <p>Clients shall call {@link #refresh()} prior to first use | 147 * <p>Clients shall call {@link #refresh()} prior to first use |
| 97 * @return collection of records in no particular order, may be empty if none applied | 148 * @return collection of records in no particular order, may be empty if none applied |
| 98 */ | 149 */ |
| 99 public List<PatchRecord> getAppliedPatches() { | 150 public List<PatchRecord> getAppliedPatches() { |
| 108 */ | 159 */ |
| 109 public List<PatchRecord> getAllKnownPatches() { | 160 public List<PatchRecord> getAllKnownPatches() { |
| 110 return Collections.unmodifiableList(allKnown); | 161 return Collections.unmodifiableList(allKnown); |
| 111 } | 162 } |
| 112 | 163 |
| 164 /** | |
| 165 * Name of the patch queue <code>hg qqueue --active</code> which is active now. | |
| 166 * @return patch queue name | |
| 167 */ | |
| 168 public String getActiveQueueName() { | |
| 169 return activeQueue; | |
| 170 } | |
| 171 | |
| 172 /** | |
| 173 * Patch queues known in the repository, <code>hg qqueue -l</code> analog. | |
| 174 * There's at least one patch queue (default one names 'patches'). Only one patch queue at a time is active. | |
| 175 * | |
| 176 * @return names of patch queues | |
| 177 */ | |
| 178 public List<String> getQueueNames() { | |
| 179 return Collections.unmodifiableList(queueNames); | |
| 180 } | |
| 181 | |
| 113 public class PatchRecord { | 182 public class PatchRecord { |
| 114 private final Nodeid nodeid; | 183 private final Nodeid nodeid; |
| 115 private final String name; | 184 private final String name; |
| 116 private final Path location; | 185 private final Path location; |
| 186 | |
| 187 // hashCode/equals might be useful if cons becomes public | |
| 117 | 188 |
| 118 PatchRecord(Nodeid revision, String name, Path diffLocation) { | 189 PatchRecord(Nodeid revision, String name, Path diffLocation) { |
| 119 nodeid = revision; | 190 nodeid = revision; |
| 120 this.name = name; | 191 this.name = name; |
| 121 this.location = diffLocation; | 192 this.location = diffLocation; |
| 160 | 231 |
| 161 class LineReader { | 232 class LineReader { |
| 162 | 233 |
| 163 private final File file; | 234 private final File file; |
| 164 private final LogFacility log; | 235 private final LogFacility log; |
| 236 private boolean trimLines = true; | |
| 237 private boolean skipEmpty = true; | |
| 238 private String ignoreThatStars = null; | |
| 165 | 239 |
| 166 LineReader(File f, LogFacility logFacility) { | 240 LineReader(File f, LogFacility logFacility) { |
| 167 file = f; | 241 file = f; |
| 168 log = logFacility; | 242 log = logFacility; |
| 243 } | |
| 244 | |
| 245 /** | |
| 246 * default: <code>true</code> | |
| 247 * <code>false</code> to return line as is | |
| 248 */ | |
| 249 LineReader trimLines(boolean trim) { | |
| 250 trimLines = trim; | |
| 251 return this; | |
| 252 } | |
| 253 | |
| 254 /** | |
| 255 * default: <code>true</code> | |
| 256 * <code>false</code> to pass empty lines to consumer | |
| 257 */ | |
| 258 LineReader skipEmpty(boolean skip) { | |
| 259 skipEmpty = skip; | |
| 260 return this; | |
| 261 } | |
| 262 | |
| 263 /** | |
| 264 * default: doesn't skip any line. | |
| 265 * set e.g. to "#" or "//" to skip lines that start with such prefix | |
| 266 */ | |
| 267 LineReader ignoreLineComments(String lineStart) { | |
| 268 ignoreThatStars = lineStart; | |
| 269 return this; | |
| 169 } | 270 } |
| 170 | 271 |
| 171 <T> void read(LineConsumer<T> consumer, T paramObj) throws HgInvalidFileException { | 272 <T> void read(LineConsumer<T> consumer, T paramObj) throws HgInvalidFileException { |
| 172 BufferedReader statusFileReader = null; | 273 BufferedReader statusFileReader = null; |
| 173 try { | 274 try { |
| 174 // consumer.begin(file, paramObj); | 275 // consumer.begin(file, paramObj); |
| 175 statusFileReader = new BufferedReader(new FileReader(file)); | 276 statusFileReader = new BufferedReader(new FileReader(file)); |
| 176 String line; | 277 String line; |
| 177 boolean ok = true; | 278 boolean ok = true; |
| 178 while (ok && (line = statusFileReader.readLine()) != null) { | 279 while (ok && (line = statusFileReader.readLine()) != null) { |
| 179 line = line.trim(); | 280 if (trimLines) { |
| 180 if (line.length() > 0) { | 281 line = line.trim(); |
| 282 } | |
| 283 if (ignoreThatStars != null && line.startsWith(ignoreThatStars)) { | |
| 284 continue; | |
| 285 } | |
| 286 if (!skipEmpty || line.length() > 0) { | |
| 181 ok = consumer.consume(line, paramObj); | 287 ok = consumer.consume(line, paramObj); |
| 182 } | 288 } |
| 183 } | 289 } |
| 184 } catch (IOException ex) { | 290 } catch (IOException ex) { |
| 185 throw new HgInvalidFileException(ex.getMessage(), ex, file); | 291 throw new HgInvalidFileException(ex.getMessage(), ex, file); |
