comparison src/org/tmatesoft/hg/internal/MergeStateBuilder.java @ 707:42b88709e41d

Merge: support 'unresolved' resolution with MergeStateBuilder
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 16 Aug 2013 19:22:59 +0200
parents b4242b7e7dfe
children
comparison
equal deleted inserted replaced
706:cd5c87d96315 707:42b88709e41d
14 * the terms of a license other than GNU General Public License 14 * the terms of a license other than GNU General Public License
15 * contact TMate Software at support@hg4j.com 15 * contact TMate Software at support@hg4j.com
16 */ 16 */
17 package org.tmatesoft.hg.internal; 17 package org.tmatesoft.hg.internal;
18 18
19 import java.io.File;
20 import java.io.FileOutputStream;
21 import java.io.IOException;
22 import java.io.OutputStream;
23 import java.nio.ByteBuffer;
24 import java.util.ArrayList;
25 import java.util.List;
26
27 import org.tmatesoft.hg.core.HgFileRevision;
19 import org.tmatesoft.hg.core.HgIOException; 28 import org.tmatesoft.hg.core.HgIOException;
29 import org.tmatesoft.hg.core.Nodeid;
30 import org.tmatesoft.hg.repo.HgManifest;
20 import org.tmatesoft.hg.repo.HgMergeState; 31 import org.tmatesoft.hg.repo.HgMergeState;
32 import org.tmatesoft.hg.repo.HgRepositoryFiles;
33 import org.tmatesoft.hg.util.ByteChannel;
34 import org.tmatesoft.hg.util.CancelledException;
21 import org.tmatesoft.hg.util.Path; 35 import org.tmatesoft.hg.util.Path;
36 import org.tmatesoft.hg.util.LogFacility.Severity;
22 37
23 /** 38 /**
24 * Constructs merge/state file 39 * Constructs merge/state file
25 * 40 *
26 * @see HgMergeState 41 * @see HgMergeState
27 * @author Artem Tikhomirov 42 * @author Artem Tikhomirov
28 * @author TMate Software Ltd. 43 * @author TMate Software Ltd.
29 */ 44 */
30 public class MergeStateBuilder { 45 public class MergeStateBuilder {
31 46
32 private final Internals repo; 47 private final Internals repo;
48 private final List<Record> unresolved = new ArrayList<Record>();
49 private Nodeid stateParent = Nodeid.NULL;
33 50
34 public MergeStateBuilder(Internals implRepo) { 51 public MergeStateBuilder(Internals implRepo) {
35 repo = implRepo; 52 repo = implRepo;
53 }
54
55 public void prepare(Nodeid nodeid) {
56 assert nodeid != null;
57 unresolved.clear();
58 stateParent = nodeid;
59 abandon();
36 } 60 }
37 61
38 public void resolved() { 62 public void resolved() {
39 throw Internals.notImplemented(); 63 throw Internals.notImplemented();
40 } 64 }
41 65
42 public void unresolved(Path file) { 66 public void unresolved(Path file, HgFileRevision first, HgFileRevision second, HgFileRevision base, HgManifest.Flags flags) throws HgIOException {
43 throw Internals.notImplemented(); 67 Record r = new Record(file, first.getPath(), second.getPath(), base.getPath(), base.getRevision(), flags);
68 final File d = mergeStateDir();
69 d.mkdirs();
70 File f = new File(d, r.hash());
71 try {
72 FileOutputStream fos = new FileOutputStream(f);
73 first.putContentTo(new OutputStreamSink(fos));
74 fos.flush();
75 fos.close();
76 unresolved.add(r);
77 } catch (IOException ex) {
78 throw new HgIOException(String.format("Failed to write content of unresolved file %s to merge state at %s", file, f), f);
79 } catch (CancelledException ex) {
80 repo.getLog().dump(getClass(), Severity.Error, ex, "Our impl doesn't throw cancellation");
81 }
44 } 82 }
45 83
46 public void serialize(Transaction tr) throws HgIOException { 84 // merge/state serialization is not a part of a transaction
85 public void serialize() throws HgIOException {
86 if (unresolved.isEmpty()) {
87 return;
88 }
89 File mergeStateFile = repo.getRepositoryFile(HgRepositoryFiles.MergeState);
90 try {
91 final byte NL = '\n';
92 FileOutputStream fos = new FileOutputStream(mergeStateFile);
93 fos.write(stateParent.toString().getBytes());
94 fos.write(NL);
95 for(Record r : unresolved) {
96 fos.write(r.key.toString().getBytes());
97 fos.write(0);
98 fos.write('u');
99 fos.write(0);
100 fos.write(r.hash().toString().getBytes());
101 fos.write(0);
102 fos.write(r.fnameA.toString().getBytes());
103 fos.write(0);
104 fos.write(r.fnameAncestor.toString().getBytes());
105 fos.write(0);
106 fos.write(r.ancestorRev.toString().getBytes());
107 fos.write(0);
108 fos.write(r.fnameB.toString().getBytes());
109 fos.write(0);
110 fos.write(r.flags.mercurialString().getBytes());
111 fos.write(NL);
112 }
113 fos.flush();
114 fos.close();
115 } catch (IOException ex) {
116 throw new HgIOException("Failed to serialize merge state", mergeStateFile);
117 }
118 }
119
120 public void abandon() {
121 File mergeStateDir = mergeStateDir();
122 try {
123 FileUtils.rmdir(mergeStateDir);
124 } catch (IOException ex) {
125 // ignore almost silently
126 repo.getLog().dump(getClass(), Severity.Warn, ex, String.format("Failed to delete merge state in %s", mergeStateDir));
127 }
128 }
129
130 private File mergeStateDir() {
131 return repo.getRepositoryFile(HgRepositoryFiles.MergeState).getParentFile();
132 }
133
134 private static class Record {
135 public final Path key;
136 public final Path fnameA, fnameB, fnameAncestor;
137 public final Nodeid ancestorRev;
138 public final HgManifest.Flags flags;
139 private String hash;
140
141 public Record(Path fname, Path a, Path b, Path ancestor, Nodeid rev, HgManifest.Flags f) {
142 key = fname;
143 fnameA = a;
144 fnameB = b;
145 fnameAncestor = ancestor;
146 ancestorRev = rev;
147 flags = f;
148 }
149
150 public String hash() {
151 if (hash == null) {
152 hash = new DigestHelper().sha1(key).asHexString();
153 }
154 return hash;
155 }
156 }
157
158 private static class OutputStreamSink implements ByteChannel {
159 private final OutputStream out;
160
161 public OutputStreamSink(OutputStream outputStream) {
162 out = outputStream;
163 }
164
165 public int write(ByteBuffer buffer) throws IOException {
166 final int toWrite = buffer.remaining();
167 if (toWrite <= 0) {
168 return 0;
169 }
170 if (buffer.hasArray()) {
171 out.write(buffer.array(), buffer.arrayOffset(), toWrite);
172 } else {
173 while (buffer.hasRemaining()) {
174 out.write(buffer.get());
175 }
176 }
177 buffer.position(buffer.limit());
178 return toWrite;
179 }
47 } 180 }
48 } 181 }