comparison src/org/tmatesoft/hg/internal/CommitFacility.java @ 618:7c0d2ce340b8

Refactor approach how content finds it way down to a commit revision
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Thu, 16 May 2013 19:46:13 +0200
parents 65c01508f002
children 868b2ffdcd5c
comparison
equal deleted inserted replaced
617:65c01508f002 618:7c0d2ce340b8
23 import static org.tmatesoft.hg.util.LogFacility.Severity.Error; 23 import static org.tmatesoft.hg.util.LogFacility.Severity.Error;
24 24
25 import java.io.File; 25 import java.io.File;
26 import java.io.FileOutputStream; 26 import java.io.FileOutputStream;
27 import java.io.IOException; 27 import java.io.IOException;
28 import java.nio.ByteBuffer;
29 import java.util.ArrayList; 28 import java.util.ArrayList;
30 import java.util.HashMap; 29 import java.util.HashMap;
31 import java.util.LinkedHashMap; 30 import java.util.LinkedHashMap;
32 import java.util.Map; 31 import java.util.Map;
33 import java.util.Set; 32 import java.util.Set;
36 35
37 import org.tmatesoft.hg.core.HgCommitCommand; 36 import org.tmatesoft.hg.core.HgCommitCommand;
38 import org.tmatesoft.hg.core.HgIOException; 37 import org.tmatesoft.hg.core.HgIOException;
39 import org.tmatesoft.hg.core.HgRepositoryLockException; 38 import org.tmatesoft.hg.core.HgRepositoryLockException;
40 import org.tmatesoft.hg.core.Nodeid; 39 import org.tmatesoft.hg.core.Nodeid;
40 import org.tmatesoft.hg.internal.DataSerializer.DataSource;
41 import org.tmatesoft.hg.repo.HgChangelog; 41 import org.tmatesoft.hg.repo.HgChangelog;
42 import org.tmatesoft.hg.repo.HgDataFile; 42 import org.tmatesoft.hg.repo.HgDataFile;
43 import org.tmatesoft.hg.util.Pair; 43 import org.tmatesoft.hg.util.Pair;
44 import org.tmatesoft.hg.util.Path; 44 import org.tmatesoft.hg.util.Path;
45 45
51 * @author TMate Software Ltd. 51 * @author TMate Software Ltd.
52 */ 52 */
53 public final class CommitFacility { 53 public final class CommitFacility {
54 private final Internals repo; 54 private final Internals repo;
55 private final int p1Commit, p2Commit; 55 private final int p1Commit, p2Commit;
56 private Map<Path, Pair<HgDataFile, ByteDataSupplier>> files = new LinkedHashMap<Path, Pair<HgDataFile, ByteDataSupplier>>(); 56 private Map<Path, Pair<HgDataFile, DataSource>> files = new LinkedHashMap<Path, Pair<HgDataFile, DataSource>>();
57 private Set<Path> removals = new TreeSet<Path>(); 57 private Set<Path> removals = new TreeSet<Path>();
58 private String branch, user; 58 private String branch, user;
59 59
60 public CommitFacility(Internals hgRepo, int parentCommit) { 60 public CommitFacility(Internals hgRepo, int parentCommit) {
61 this(hgRepo, parentCommit, NO_REVISION); 61 this(hgRepo, parentCommit, NO_REVISION);
72 72
73 public boolean isMerge() { 73 public boolean isMerge() {
74 return p1Commit != NO_REVISION && p2Commit != NO_REVISION; 74 return p1Commit != NO_REVISION && p2Commit != NO_REVISION;
75 } 75 }
76 76
77 public void add(HgDataFile dataFile, ByteDataSupplier content) { 77 public void add(HgDataFile dataFile, DataSource content) {
78 if (content == null) { 78 if (content == null) {
79 throw new IllegalArgumentException(); 79 throw new IllegalArgumentException();
80 } 80 }
81 removals.remove(dataFile.getPath()); 81 removals.remove(dataFile.getPath());
82 files.put(dataFile.getPath(), new Pair<HgDataFile, ByteDataSupplier>(dataFile, content)); 82 files.put(dataFile.getPath(), new Pair<HgDataFile, DataSource>(dataFile, content));
83 } 83 }
84 84
85 public void forget(HgDataFile dataFile) { 85 public void forget(HgDataFile dataFile) {
86 files.remove(dataFile.getPath()); 86 files.remove(dataFile.getPath());
87 removals.add(dataFile.getPath()); 87 removals.add(dataFile.getPath());
136 } 136 }
137 // 137 //
138 // Register new/changed 138 // Register new/changed
139 LinkedHashMap<Path, RevlogStream> newlyAddedFiles = new LinkedHashMap<Path, RevlogStream>(); 139 LinkedHashMap<Path, RevlogStream> newlyAddedFiles = new LinkedHashMap<Path, RevlogStream>();
140 ArrayList<Path> touchInDirstate = new ArrayList<Path>(); 140 ArrayList<Path> touchInDirstate = new ArrayList<Path>();
141 for (Pair<HgDataFile, ByteDataSupplier> e : files.values()) { 141 for (Pair<HgDataFile, DataSource> e : files.values()) {
142 HgDataFile df = e.first(); 142 HgDataFile df = e.first();
143 DataSource bds = e.second();
143 Pair<Integer, Integer> fp = fileParents.get(df.getPath()); 144 Pair<Integer, Integer> fp = fileParents.get(df.getPath());
144 if (fp == null) { 145 if (fp == null) {
145 // NEW FILE 146 // NEW FILE
146 fp = new Pair<Integer, Integer>(NO_REVISION, NO_REVISION); 147 fp = new Pair<Integer, Integer>(NO_REVISION, NO_REVISION);
147 }
148 ByteDataSupplier bds = e.second();
149 // FIXME quickfix, instead, pass ByteDataSupplier directly to RevlogStreamWriter
150 ByteBuffer bb = ByteBuffer.allocate(2048);
151 ByteArrayChannel bac = new ByteArrayChannel();
152 while (bds.read(bb) != -1) {
153 bb.flip();
154 bac.write(bb);
155 bb.clear();
156 } 148 }
157 RevlogStream contentStream; 149 RevlogStream contentStream;
158 if (df.exists()) { 150 if (df.exists()) {
159 contentStream = repo.getImplAccess().getStream(df); 151 contentStream = repo.getImplAccess().getStream(df);
160 } else { 152 } else {
163 // FIXME df doesn't get df.content updated, and clients 155 // FIXME df doesn't get df.content updated, and clients
164 // that would attempt to access newly added file after commit would fail 156 // that would attempt to access newly added file after commit would fail
165 // (despite the fact the file is in there) 157 // (despite the fact the file is in there)
166 } 158 }
167 RevlogStreamWriter fileWriter = new RevlogStreamWriter(repo, contentStream, transaction); 159 RevlogStreamWriter fileWriter = new RevlogStreamWriter(repo, contentStream, transaction);
168 Nodeid fileRev = fileWriter.addRevision(bac.toArray(), clogRevisionIndex, fp.first(), fp.second()); 160 Nodeid fileRev = fileWriter.addRevision(bds, clogRevisionIndex, fp.first(), fp.second());
169 newManifestRevision.put(df.getPath(), fileRev); 161 newManifestRevision.put(df.getPath(), fileRev);
170 touchInDirstate.add(df.getPath()); 162 touchInDirstate.add(df.getPath());
171 } 163 }
172 // 164 //
173 // Manifest 165 // Manifest
174 final ManifestEntryBuilder manifestBuilder = new ManifestEntryBuilder(); 166 final ManifestEntryBuilder manifestBuilder = new ManifestEntryBuilder(repo.buildFileNameEncodingHelper());
175 for (Map.Entry<Path, Nodeid> me : newManifestRevision.entrySet()) { 167 for (Map.Entry<Path, Nodeid> me : newManifestRevision.entrySet()) {
176 manifestBuilder.add(me.getKey().toString(), me.getValue()); 168 manifestBuilder.add(me.getKey().toString(), me.getValue());
177 } 169 }
178 RevlogStreamWriter manifestWriter = new RevlogStreamWriter(repo, repo.getImplAccess().getManifestStream(), transaction); 170 RevlogStreamWriter manifestWriter = new RevlogStreamWriter(repo, repo.getImplAccess().getManifestStream(), transaction);
179 Nodeid manifestRev = manifestWriter.addRevision(manifestBuilder.build(), clogRevisionIndex, manifestParents.first(), manifestParents.second()); 171 Nodeid manifestRev = manifestWriter.addRevision(manifestBuilder, clogRevisionIndex, manifestParents.first(), manifestParents.second());
180 // 172 //
181 // Changelog 173 // Changelog
182 final ChangelogEntryBuilder changelogBuilder = new ChangelogEntryBuilder(); 174 final ChangelogEntryBuilder changelogBuilder = new ChangelogEntryBuilder();
183 changelogBuilder.setModified(files.keySet()); 175 changelogBuilder.setModified(files.keySet());
184 changelogBuilder.branch(branch == null ? DEFAULT_BRANCH_NAME : branch); 176 changelogBuilder.branch(branch == null ? DEFAULT_BRANCH_NAME : branch);
185 changelogBuilder.user(String.valueOf(user)); 177 changelogBuilder.user(String.valueOf(user));
186 byte[] clogContent = changelogBuilder.build(manifestRev, message); 178 changelogBuilder.manifest(manifestRev).comment(message);
187 RevlogStreamWriter changelogWriter = new RevlogStreamWriter(repo, repo.getImplAccess().getChangelogStream(), transaction); 179 RevlogStreamWriter changelogWriter = new RevlogStreamWriter(repo, repo.getImplAccess().getChangelogStream(), transaction);
188 Nodeid changesetRev = changelogWriter.addRevision(clogContent, clogRevisionIndex, p1Commit, p2Commit); 180 Nodeid changesetRev = changelogWriter.addRevision(changelogBuilder, clogRevisionIndex, p1Commit, p2Commit);
189 // TODO move fncache update to an external facility, along with dirstate and bookmark update 181 // TODO move fncache update to an external facility, along with dirstate and bookmark update
190 if (!newlyAddedFiles.isEmpty() && repo.fncacheInUse()) { 182 if (!newlyAddedFiles.isEmpty() && repo.fncacheInUse()) {
191 FNCacheFile fncache = new FNCacheFile(repo); 183 FNCacheFile fncache = new FNCacheFile(repo);
192 for (Path p : newlyAddedFiles.keySet()) { 184 for (Path p : newlyAddedFiles.keySet()) {
193 fncache.addIndex(p); 185 fncache.addIndex(p);
263 return NO_REVISION; 255 return NO_REVISION;
264 } 256 }
265 return repo.getManifest().getRevisionIndex(manifestRev); 257 return repo.getManifest().getRevisionIndex(manifestRev);
266 } 258 }
267 */ 259 */
268
269 // unlike DataAccess (which provides structured access), this one
270 // deals with a sequence of bytes, when there's no need in structure of the data
271 // FIXME java.nio.ReadableByteChannel or ByteStream/ByteSequence(read, length, reset)
272 // SHALL be inline with util.ByteChannel, reading bytes from HgDataFile, preferably DataAccess#readBytes(BB) to match API,
273 // and a wrap for ByteVector
274 public interface ByteDataSupplier { // TODO look if can resolve DataAccess in HgCloneCommand visibility issue
275 // FIXME needs lifecycle, e.g. for supplier that reads from WC
276 int read(ByteBuffer buf);
277 }
278
279 public interface ByteDataConsumer {
280 void write(ByteBuffer buf);
281 }
282 } 260 }