comparison src/org/tmatesoft/hg/repo/ext/MqManager.java @ 463:a0507a9f3da0 smartgit3

Initial support for MqExtension
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 20 Jun 2012 21:16:21 +0200
parents
children 1a3c18d57a8e
comparison
equal deleted inserted replaced
455:281cfb60e2ef 463:a0507a9f3da0
1 /*
2 * Copyright (c) 2012 TMate Software Ltd
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * For information on how to redistribute this software under
14 * the terms of a license other than GNU General Public License
15 * contact TMate Software at support@hg4j.com
16 */
17 package org.tmatesoft.hg.repo.ext;
18
19 import java.io.BufferedReader;
20 import java.io.File;
21 import java.io.FileReader;
22 import java.io.IOException;
23 import java.util.Collections;
24 import java.util.LinkedList;
25 import java.util.List;
26
27 import org.tmatesoft.hg.core.HgInvalidControlFileException;
28 import org.tmatesoft.hg.core.HgInvalidFileException;
29 import org.tmatesoft.hg.core.Nodeid;
30 import org.tmatesoft.hg.repo.HgInternals;
31 import org.tmatesoft.hg.repo.HgRepository;
32 import org.tmatesoft.hg.util.LogFacility;
33 import org.tmatesoft.hg.util.Path;
34
35 /**
36 * Mercurial Queues Support.
37 * Access to MqExtension functionality.
38 *
39 * @author Artem Tikhomirov
40 * @author TMate Software Ltd.
41 */
42 public class MqManager {
43
44 private final HgRepository repo;
45 private List<PatchRecord> applied = Collections.emptyList();
46 private List<PatchRecord> allKnown = Collections.emptyList();
47
48 public MqManager(HgRepository hgRepo) {
49 repo = hgRepo;
50 }
51
52 /**
53 * Updates manager with up-to-date state of the mercurial queues.
54 */
55 public void refresh() throws HgInvalidControlFileException {
56 File repoDir = HgInternals.getRepositoryDir(repo);
57 final LogFacility log = HgInternals.getContext(repo).getLog();
58 final File fileStatus = new File(repoDir, "patches/status");
59 final File fileSeries = new File(repoDir, "patches/series");
60 try {
61 if (fileStatus.isFile()) {
62 new LineReader(fileStatus, log).read(new LineConsumer<List<PatchRecord>>() {
63
64 public boolean consume(String line, List<PatchRecord> result) throws IOException {
65 int sep = line.indexOf(':');
66 if (sep == -1) {
67 log.warn(MqManager.class, "Bad line in %s:%s", fileStatus.getPath(), line);
68 return true;
69 }
70 Nodeid nid = Nodeid.fromAscii(line.substring(0, sep));
71 String name = new String(line.substring(sep+1));
72 result.add(new PatchRecord(nid, name, Path.create(".hg/patches/" + name)));
73 return true;
74 }
75 }, applied = new LinkedList<PatchRecord>());
76 }
77 if (fileSeries.isFile()) {
78 new LineReader(fileSeries, log).read(new LineConsumer<List<PatchRecord>>() {
79
80 public boolean consume(String line, List<PatchRecord> result) throws IOException {
81 result.add(new PatchRecord(null, line, Path.create(".hg/patches/" + line)));
82 return true;
83 }
84 }, allKnown = new LinkedList<PatchRecord>());
85 }
86 } catch (HgInvalidFileException ex) {
87 HgInvalidControlFileException th = new HgInvalidControlFileException(ex.getMessage(), ex.getCause(), ex.getFile());
88 th.setStackTrace(ex.getStackTrace());
89 throw th;
90 }
91 }
92
93 /**
94 * Subset of the patches from the queue that were already applied to the repository
95 *
96 * <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
98 */
99 public List<PatchRecord> getAppliedPatches() {
100 return Collections.unmodifiableList(applied);
101 }
102
103 /**
104 * All of the patches that MQ knows about for this repository
105 *
106 * <p>Clients shall call {@link #refresh()} prior to first use
107 * @return collection of records in no particular order, may be empty if there are no patches in the queue
108 */
109 public List<PatchRecord> getAllKnownPatches() {
110 return Collections.unmodifiableList(allKnown);
111 }
112
113 public class PatchRecord {
114 private final Nodeid nodeid;
115 private final String name;
116 private final Path location;
117
118 PatchRecord(Nodeid revision, String name, Path diffLocation) {
119 nodeid = revision;
120 this.name = name;
121 this.location = diffLocation;
122 }
123
124 /**
125 * Identifies changeset of the patch that has been applied to the repository
126 *
127 * @return changeset revision or <code>null</code> if this patch is not yet applied
128 */
129 public Nodeid getRevision() {
130 return nodeid;
131 }
132
133 /**
134 * Identifies patch, either based on a user-supplied name (<code>hg qnew <i>patch-name</i></code>) or
135 * an automatically generated name (like <code><i>revisionIndex</i>.diff</code> for imported changesets).
136 * Clients shall not rely on this naming scheme, though.
137 *
138 * @return never <code>null</code>
139 */
140 public String getName() {
141 return name;
142 }
143
144 /**
145 * Location of diff file with the patch, relative to repository root
146 * @return path to the patch, never <code>null</code>
147 */
148 public Path getPatchLocation() {
149 return location;
150 }
151 }
152
153 // TODO refine API and extract into separate classes
154
155 interface LineConsumer<T> {
156 // boolean begin(File f, T paramObj) throws IOException;
157 boolean consume(String line, T paramObj) throws IOException;
158 // boolean end(File f, T paramObj) throws IOException;
159 }
160
161 class LineReader {
162
163 private final File file;
164 private final LogFacility log;
165
166 LineReader(File f, LogFacility logFacility) {
167 file = f;
168 log = logFacility;
169 }
170
171 <T> void read(LineConsumer<T> consumer, T paramObj) throws HgInvalidFileException {
172 BufferedReader statusFileReader = null;
173 try {
174 // consumer.begin(file, paramObj);
175 statusFileReader = new BufferedReader(new FileReader(file));
176 String line;
177 boolean ok = true;
178 while (ok && (line = statusFileReader.readLine()) != null) {
179 line = line.trim();
180 if (line.length() > 0) {
181 ok = consumer.consume(line, paramObj);
182 }
183 }
184 } catch (IOException ex) {
185 throw new HgInvalidFileException(ex.getMessage(), ex, file);
186 } finally {
187 try {
188 statusFileReader.close();
189 } catch (IOException ex) {
190 log.warn(MqManager.class, ex, null);
191 }
192 // try {
193 // consumer.end(file, paramObj);
194 // } catch (IOException ex) {
195 // log.warn(MqManager.class, ex, null);
196 // }
197 }
198 }
199 }
200 }