comparison src/org/tmatesoft/hg/repo/ext/MqManager.java @ 480:f3fab7a20841

Refactor LineReader utility as stanalone class to facilitate reuse
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Tue, 17 Jul 2012 22:14:21 +0200
parents 0e34b8f3946a
children b3c16d1aede0
comparison
equal deleted inserted replaced
479:59b7c817bc4d 480:f3fab7a20841
16 */ 16 */
17 package org.tmatesoft.hg.repo.ext; 17 package org.tmatesoft.hg.repo.ext;
18 18
19 import static org.tmatesoft.hg.util.LogFacility.Severity.Warn; 19 import static org.tmatesoft.hg.util.LogFacility.Severity.Warn;
20 20
21 import java.io.BufferedReader;
22 import java.io.File; 21 import java.io.File;
23 import java.io.FileReader;
24 import java.io.IOException; 22 import java.io.IOException;
25 import java.util.ArrayList; 23 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Collections; 24 import java.util.Collections;
28 import java.util.HashMap; 25 import java.util.HashMap;
29 import java.util.LinkedList; 26 import java.util.LinkedList;
30 import java.util.List; 27 import java.util.List;
31 import java.util.Map; 28 import java.util.Map;
32 29
33 import org.tmatesoft.hg.core.Nodeid; 30 import org.tmatesoft.hg.core.Nodeid;
31 import org.tmatesoft.hg.internal.LineReader;
34 import org.tmatesoft.hg.repo.HgInternals; 32 import org.tmatesoft.hg.repo.HgInternals;
35 import org.tmatesoft.hg.repo.HgInvalidControlFileException; 33 import org.tmatesoft.hg.repo.HgInvalidControlFileException;
36 import org.tmatesoft.hg.repo.HgInvalidFileException; 34 import org.tmatesoft.hg.repo.HgInvalidFileException;
37 import org.tmatesoft.hg.repo.HgRepository; 35 import org.tmatesoft.hg.repo.HgRepository;
38 import org.tmatesoft.hg.util.LogFacility; 36 import org.tmatesoft.hg.util.LogFacility;
69 final LogFacility log = HgInternals.getContext(repo).getLog(); 67 final LogFacility log = HgInternals.getContext(repo).getLog();
70 try { 68 try {
71 File queues = new File(repoDir, "patches.queues"); 69 File queues = new File(repoDir, "patches.queues");
72 if (queues.isFile()) { 70 if (queues.isFile()) {
73 LineReader lr = new LineReader(queues, log).trimLines(true).skipEmpty(true); 71 LineReader lr = new LineReader(queues, log).trimLines(true).skipEmpty(true);
74 lr.read(new SimpleLineCollector(), queueNames = new LinkedList<String>()); 72 lr.read(new LineReader.SimpleLineCollector(), queueNames = new LinkedList<String>());
75 } 73 }
76 final String queueLocation; // path under .hg to patch queue information (status, series and diff files) 74 final String queueLocation; // path under .hg to patch queue information (status, series and diff files)
77 File activeQueueFile = new File(repoDir, "patches.queue"); 75 File activeQueueFile = new File(repoDir, "patches.queue");
78 // file is there only if it's not default queue ('patches') that is active 76 // file is there only if it's not default queue ('patches') that is active
79 if (activeQueueFile.isFile()) { 77 if (activeQueueFile.isFile()) {
80 ArrayList<String> contents = new ArrayList<String>(); 78 ArrayList<String> contents = new ArrayList<String>();
81 new LineReader(activeQueueFile, log).read(new SimpleLineCollector(), contents); 79 new LineReader(activeQueueFile, log).read(new LineReader.SimpleLineCollector(), contents);
82 if (contents.isEmpty()) { 80 if (contents.isEmpty()) {
83 log.dump(getClass(), Warn, "File %s with active queue name is empty", activeQueueFile.getName()); 81 log.dump(getClass(), Warn, "File %s with active queue name is empty", activeQueueFile.getName());
84 activeQueue = PATCHES_DIR; 82 activeQueue = PATCHES_DIR;
85 queueLocation = PATCHES_DIR + '/'; 83 queueLocation = PATCHES_DIR + '/';
86 } else { 84 } else {
102 } 100 }
103 }; 101 };
104 final File fileStatus = new File(repoDir, queueLocation + "status"); 102 final File fileStatus = new File(repoDir, queueLocation + "status");
105 final File fileSeries = new File(repoDir, queueLocation + "series"); 103 final File fileSeries = new File(repoDir, queueLocation + "series");
106 if (fileStatus.isFile()) { 104 if (fileStatus.isFile()) {
107 new LineReader(fileStatus, log).read(new LineConsumer<List<PatchRecord>>() { 105 new LineReader(fileStatus, log).read(new LineReader.LineConsumer<List<PatchRecord>>() {
108 106
109 public boolean consume(String line, List<PatchRecord> result) throws IOException { 107 public boolean consume(String line, List<PatchRecord> result) throws IOException {
110 int sep = line.indexOf(':'); 108 int sep = line.indexOf(':');
111 if (sep == -1) { 109 if (sep == -1) {
112 log.dump(MqManager.class, Warn, "Bad line in %s:%s", fileStatus.getPath(), line); 110 log.dump(MqManager.class, Warn, "Bad line in %s:%s", fileStatus.getPath(), line);
123 final Map<String,PatchRecord> name2patch = new HashMap<String, PatchRecord>(); 121 final Map<String,PatchRecord> name2patch = new HashMap<String, PatchRecord>();
124 for (PatchRecord pr : applied) { 122 for (PatchRecord pr : applied) {
125 name2patch.put(pr.getName(), pr); 123 name2patch.put(pr.getName(), pr);
126 } 124 }
127 LinkedList<String> knownPatchNames = new LinkedList<String>(); 125 LinkedList<String> knownPatchNames = new LinkedList<String>();
128 new LineReader(fileSeries, log).read(new SimpleLineCollector(), knownPatchNames); 126 new LineReader(fileSeries, log).read(new LineReader.SimpleLineCollector(), knownPatchNames);
129 // XXX read other queues? 127 // XXX read other queues?
130 allKnown = new ArrayList<PatchRecord>(knownPatchNames.size()); 128 allKnown = new ArrayList<PatchRecord>(knownPatchNames.size());
131 for (String name : knownPatchNames) { 129 for (String name : knownPatchNames) {
132 PatchRecord pr = name2patch.get(name); 130 PatchRecord pr = name2patch.get(name);
133 if (pr == null) { 131 if (pr == null) {
138 } 136 }
139 } catch (HgInvalidFileException ex) { 137 } catch (HgInvalidFileException ex) {
140 HgInvalidControlFileException th = new HgInvalidControlFileException(ex.getMessage(), ex.getCause(), ex.getFile()); 138 HgInvalidControlFileException th = new HgInvalidControlFileException(ex.getMessage(), ex.getCause(), ex.getFile());
141 th.setStackTrace(ex.getStackTrace()); 139 th.setStackTrace(ex.getStackTrace());
142 throw th; 140 throw th;
143 }
144 }
145
146 static class SimpleLineCollector implements LineConsumer<Collection<String>> {
147
148 public boolean consume(String line, Collection<String> result) throws IOException {
149 result.add(line);
150 return true;
151 } 141 }
152 } 142 }
153 143
154 /** 144 /**
155 * Number of patches not yet applied 145 * Number of patches not yet applied
244 String fmt = "mq.PatchRecord[name:%s; %spath:%s]"; 234 String fmt = "mq.PatchRecord[name:%s; %spath:%s]";
245 String ni = nodeid != null ? String.format("applied as: %s; ", nodeid.shortNotation()) : ""; 235 String ni = nodeid != null ? String.format("applied as: %s; ", nodeid.shortNotation()) : "";
246 return String.format(fmt, name, ni, location); 236 return String.format(fmt, name, ni, location);
247 } 237 }
248 } 238 }
249
250 // TODO refine API and extract into separate classes
251
252 interface LineConsumer<T> {
253 // boolean begin(File f, T paramObj) throws IOException;
254 boolean consume(String line, T paramObj) throws IOException;
255 // boolean end(File f, T paramObj) throws IOException;
256 }
257
258 class LineReader {
259
260 private final File file;
261 private final LogFacility log;
262 private boolean trimLines = true;
263 private boolean skipEmpty = true;
264 private String ignoreThatStars = null;
265
266 LineReader(File f, LogFacility logFacility) {
267 file = f;
268 log = logFacility;
269 }
270
271 /**
272 * default: <code>true</code>
273 * <code>false</code> to return line as is
274 */
275 LineReader trimLines(boolean trim) {
276 trimLines = trim;
277 return this;
278 }
279
280 /**
281 * default: <code>true</code>
282 * <code>false</code> to pass empty lines to consumer
283 */
284 LineReader skipEmpty(boolean skip) {
285 skipEmpty = skip;
286 return this;
287 }
288
289 /**
290 * default: doesn't skip any line.
291 * set e.g. to "#" or "//" to skip lines that start with such prefix
292 */
293 LineReader ignoreLineComments(String lineStart) {
294 ignoreThatStars = lineStart;
295 return this;
296 }
297
298 <T> void read(LineConsumer<T> consumer, T paramObj) throws HgInvalidFileException {
299 BufferedReader statusFileReader = null;
300 try {
301 // consumer.begin(file, paramObj);
302 statusFileReader = new BufferedReader(new FileReader(file));
303 String line;
304 boolean ok = true;
305 while (ok && (line = statusFileReader.readLine()) != null) {
306 if (trimLines) {
307 line = line.trim();
308 }
309 if (ignoreThatStars != null && line.startsWith(ignoreThatStars)) {
310 continue;
311 }
312 if (!skipEmpty || line.length() > 0) {
313 ok = consumer.consume(line, paramObj);
314 }
315 }
316 } catch (IOException ex) {
317 throw new HgInvalidFileException(ex.getMessage(), ex, file);
318 } finally {
319 try {
320 statusFileReader.close();
321 } catch (IOException ex) {
322 log.dump(MqManager.class, Warn, ex, null);
323 }
324 // try {
325 // consumer.end(file, paramObj);
326 // } catch (IOException ex) {
327 // log.warn(MqManager.class, ex, null);
328 // }
329 }
330 }
331 }
332 } 239 }