annotate src/org/tmatesoft/hg/internal/BundleGenerator.java @ 709:497e697636fc

Report merged lines as changed block if possible, not as a sequence of added/deleted blocks. To facilitate access to merge parent lines AddBlock got mergeLineAt() method that reports index of the line in the second parent (if any), while insertedAt() has been changed to report index in the first parent always
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 21 Aug 2013 16:23:27 +0200
parents 52af7f62e731
children
rev   line source
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
1 /*
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
2 * Copyright (c) 2013 TMate Software Ltd
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
3 *
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
4 * This program is free software; you can redistribute it and/or modify
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
5 * it under the terms of the GNU General Public License as published by
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
6 * the Free Software Foundation; version 2 of the License.
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
7 *
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
8 * This program is distributed in the hope that it will be useful,
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
11 * GNU General Public License for more details.
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
12 *
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
13 * For information on how to redistribute this software under
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
14 * the terms of a license other than GNU General Public License
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
15 * contact TMate Software at support@hg4j.com
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
16 */
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
17 package org.tmatesoft.hg.internal;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
18
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
19 import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
20 import static org.tmatesoft.hg.repo.HgRepository.TIP;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
21
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
22 import java.io.File;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
23 import java.io.FileOutputStream;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
24 import java.io.IOException;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
25 import java.util.ArrayList;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
26 import java.util.Arrays;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
27 import java.util.Collection;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
28 import java.util.Collections;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
29 import java.util.Comparator;
645
14dac192aa26 Push: phase2 - upload bundle with changes to remote server
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 644
diff changeset
30 import java.util.HashSet;
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
31 import java.util.List;
645
14dac192aa26 Push: phase2 - upload bundle with changes to remote server
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 644
diff changeset
32 import java.util.Set;
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
33
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
34 import org.tmatesoft.hg.core.HgIOException;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
35 import org.tmatesoft.hg.core.Nodeid;
645
14dac192aa26 Push: phase2 - upload bundle with changes to remote server
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 644
diff changeset
36 import org.tmatesoft.hg.internal.DataSerializer.OutputStreamSerializer;
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
37 import org.tmatesoft.hg.internal.Patch.PatchDataSource;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
38 import org.tmatesoft.hg.repo.HgChangelog;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
39 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
40 import org.tmatesoft.hg.repo.HgDataFile;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
41 import org.tmatesoft.hg.repo.HgInvalidControlFileException;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
42 import org.tmatesoft.hg.repo.HgManifest;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
43 import org.tmatesoft.hg.repo.HgRuntimeException;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
44
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
45 /**
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
46 * @see http://mercurial.selenic.com/wiki/BundleFormat
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
47 * @author Artem Tikhomirov
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
48 * @author TMate Software Ltd.
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
49 */
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
50 public class BundleGenerator {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
51
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
52 private final Internals repo;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
53
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
54 public BundleGenerator(Internals hgRepo) {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
55 repo = hgRepo;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
56 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
57
670
52af7f62e731 AIOOBE in BundleGenerator.ChunkGenerator.iterate when there are no outgoing changes on push
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 668
diff changeset
58 /**
52af7f62e731 AIOOBE in BundleGenerator.ChunkGenerator.iterate when there are no outgoing changes on push
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 668
diff changeset
59 * @return never <code>null</code>. empty file if no changesets were written
52af7f62e731 AIOOBE in BundleGenerator.ChunkGenerator.iterate when there are no outgoing changes on push
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 668
diff changeset
60 */
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
61 public File create(List<Nodeid> changesets) throws HgIOException, IOException {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
62 final HgChangelog clog = repo.getRepo().getChangelog();
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
63 final HgManifest manifest = repo.getRepo().getManifest();
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
64 IntVector clogRevsVector = new IntVector(changesets.size(), 0);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
65 for (Nodeid n : changesets) {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
66 clogRevsVector.add(clog.getRevisionIndex(n));
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
67 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
68 clogRevsVector.sort(true);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
69 final int[] clogRevs = clogRevsVector.toArray();
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
70 final IntMap<Nodeid> clogMap = new IntMap<Nodeid>(changesets.size());
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
71 final IntVector manifestRevs = new IntVector(changesets.size(), 0);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
72 final List<HgDataFile> files = new ArrayList<HgDataFile>();
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
73 clog.range(new HgChangelog.Inspector() {
645
14dac192aa26 Push: phase2 - upload bundle with changes to remote server
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 644
diff changeset
74 private Set<String> seenFiles = new HashSet<String>();
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
75 public void next(int revisionIndex, Nodeid nodeid, RawChangeset cset) throws HgRuntimeException {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
76 clogMap.put(revisionIndex, nodeid);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
77 manifestRevs.add(manifest.getRevisionIndex(cset.manifest()));
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
78 for (String f : cset.files()) {
645
14dac192aa26 Push: phase2 - upload bundle with changes to remote server
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 644
diff changeset
79 if (seenFiles.contains(f)) {
14dac192aa26 Push: phase2 - upload bundle with changes to remote server
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 644
diff changeset
80 continue;
14dac192aa26 Push: phase2 - upload bundle with changes to remote server
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 644
diff changeset
81 }
14dac192aa26 Push: phase2 - upload bundle with changes to remote server
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 644
diff changeset
82 seenFiles.add(f);
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
83 HgDataFile df = repo.getRepo().getFileNode(f);
645
14dac192aa26 Push: phase2 - upload bundle with changes to remote server
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 644
diff changeset
84 files.add(df);
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
85 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
86 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
87 }, clogRevs);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
88 manifestRevs.sort(true);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
89 //
651
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
90 final File bundleFile = File.createTempFile("hg4j-", ".bundle");
670
52af7f62e731 AIOOBE in BundleGenerator.ChunkGenerator.iterate when there are no outgoing changes on push
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 668
diff changeset
91 if (clogRevs.length == 0) {
52af7f62e731 AIOOBE in BundleGenerator.ChunkGenerator.iterate when there are no outgoing changes on push
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 668
diff changeset
92 // nothing to write
52af7f62e731 AIOOBE in BundleGenerator.ChunkGenerator.iterate when there are no outgoing changes on push
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 668
diff changeset
93 return bundleFile;
52af7f62e731 AIOOBE in BundleGenerator.ChunkGenerator.iterate when there are no outgoing changes on push
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 668
diff changeset
94 }
645
14dac192aa26 Push: phase2 - upload bundle with changes to remote server
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 644
diff changeset
95 final FileOutputStream osBundle = new FileOutputStream(bundleFile);
14dac192aa26 Push: phase2 - upload bundle with changes to remote server
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 644
diff changeset
96 final OutputStreamSerializer outRaw = new OutputStreamSerializer(osBundle);
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
97 outRaw.write("HG10UN".getBytes(), 0, 6);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
98 //
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
99 RevlogStream clogStream = repo.getImplAccess().getChangelogStream();
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
100 new ChunkGenerator(outRaw, clogMap).iterate(clogStream, clogRevs);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
101 outRaw.writeInt(0); // null chunk for changelog group
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
102 //
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
103 RevlogStream manifestStream = repo.getImplAccess().getManifestStream();
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
104 new ChunkGenerator(outRaw, clogMap).iterate(manifestStream, manifestRevs.toArray(true));
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
105 outRaw.writeInt(0); // null chunk for manifest group
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
106 //
667
fba85bc1dfb8 Refactoring: move all encoding/decoding operations into single place, EncodingHelper
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 651
diff changeset
107 EncodingHelper fnEncoder = repo.buildFileNameEncodingHelper();
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
108 for (HgDataFile df : sortedByName(files)) {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
109 RevlogStream s = repo.getImplAccess().getStream(df);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
110 final IntVector fileRevs = new IntVector();
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
111 s.iterate(0, TIP, false, new RevlogStream.Inspector() {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
112
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
113 public void next(int revisionIndex, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) throws HgRuntimeException {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
114 if (Arrays.binarySearch(clogRevs, linkRevision) >= 0) {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
115 fileRevs.add(revisionIndex);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
116 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
117 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
118 });
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
119 fileRevs.sort(true);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
120 if (!fileRevs.isEmpty()) {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
121 // although BundleFormat page says "filename length, filename" for a file,
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
122 // in fact there's a sort of 'filename chunk', i.e. filename length field includes
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
123 // not only length of filename, but also length of the field itseld, i.e. filename.length+sizeof(int)
667
fba85bc1dfb8 Refactoring: move all encoding/decoding operations into single place, EncodingHelper
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 651
diff changeset
124 byte[] fnameBytes = fnEncoder.toBundle(df.getPath());
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
125 outRaw.writeInt(fnameBytes.length + 4);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
126 outRaw.writeByte(fnameBytes);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
127 new ChunkGenerator(outRaw, clogMap).iterate(s, fileRevs.toArray(true));
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
128 outRaw.writeInt(0); // null chunk for file group
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
129 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
130 }
645
14dac192aa26 Push: phase2 - upload bundle with changes to remote server
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 644
diff changeset
131 outRaw.writeInt(0); // null chunk to indicate no more files (although BundleFormat page doesn't mention this)
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
132 outRaw.done();
645
14dac192aa26 Push: phase2 - upload bundle with changes to remote server
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 644
diff changeset
133 osBundle.flush();
14dac192aa26 Push: phase2 - upload bundle with changes to remote server
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 644
diff changeset
134 osBundle.close();
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
135 //return new HgBundle(repo.getSessionContext(), repo.getDataAccess(), bundleFile);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
136 return bundleFile;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
137 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
138
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
139 private static Collection<HgDataFile> sortedByName(List<HgDataFile> files) {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
140 Collections.sort(files, new Comparator<HgDataFile>() {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
141
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
142 public int compare(HgDataFile o1, HgDataFile o2) {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
143 return o1.getPath().compareTo(o2.getPath());
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
144 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
145 });
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
146 return files;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
147 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
148
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
149 private static class ChunkGenerator implements RevlogStream.Inspector {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
150
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
151 private final DataSerializer ds;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
152 private final IntMap<Nodeid> parentMap;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
153 private final IntMap<Nodeid> clogMap;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
154 private byte[] prevContent;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
155 private int startParent;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
156
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
157 public ChunkGenerator(DataSerializer dataSerializer, IntMap<Nodeid> clogNodeidMap) {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
158 ds = dataSerializer;
651
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
159 parentMap = new IntMap<Nodeid>(clogNodeidMap.size());
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
160 clogMap = clogNodeidMap;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
161 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
162
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
163 public void iterate(RevlogStream s, int[] revisions) throws HgRuntimeException {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
164 int[] p = s.parents(revisions[0], new int[2]);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
165 startParent = p[0];
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
166 int[] revs2read;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
167 if (startParent == NO_REVISION) {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
168 revs2read = revisions;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
169 prevContent = new byte[0];
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
170 } else {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
171 revs2read = new int[revisions.length + 1];
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
172 revs2read[0] = startParent;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
173 System.arraycopy(revisions, 0, revs2read, 1, revisions.length);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
174 }
651
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
175 // FIXME this is a hack to fill parentsMap with
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
176 // parents of elements that we are not going to meet with regular
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
177 // iteration, e.g. changes from a different branch (with some older parent),
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
178 // scenario: two revisions added to two different branches
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
179 // revisions[10, 11], parents(10) == 9, parents(11) == 7
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
180 // revs2read == [9,10,11], and parentsMap lacks entry for parent rev7.
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
181 fillMissingParentsMap(s, revisions);
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
182 s.iterate(revs2read, true, this);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
183 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
184
651
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
185 private void fillMissingParentsMap(RevlogStream s, int[] revisions) throws HgRuntimeException {
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
186 int[] p = new int[2];
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
187 for (int i = 1; i < revisions.length; i++) {
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
188 s.parents(revisions[i], p);
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
189 if (p[0] != NO_REVISION && Arrays.binarySearch(revisions, p[0]) < 0) {
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
190 parentMap.put(p[0], Nodeid.fromBinary(s.nodeid(p[0]), 0));
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
191 }
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
192 if (p[1] != NO_REVISION && Arrays.binarySearch(revisions, p[1]) < 0) {
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
193 parentMap.put(p[1], Nodeid.fromBinary(s.nodeid(p[1]), 0));
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
194 }
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
195 }
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
196 }
6e98d34eaca8 Push: tests (push to empty, push changes, respect secret)
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents: 645
diff changeset
197
644
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
198 public void next(int revisionIndex, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) throws HgRuntimeException {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
199 try {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
200 parentMap.put(revisionIndex, Nodeid.fromBinary(nodeid, 0));
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
201 byte[] nextContent = data.byteArray();
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
202 data.done();
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
203 if (revisionIndex == startParent) {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
204 prevContent = nextContent;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
205 return;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
206 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
207 Patch p = GeneratePatchInspector.delta(prevContent, nextContent);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
208 prevContent = nextContent;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
209 nextContent = null;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
210 PatchDataSource pds = p.new PatchDataSource();
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
211 int len = pds.serializeLength() + 84;
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
212 ds.writeInt(len);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
213 ds.write(nodeid, 0, Nodeid.SIZE);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
214 if (parent1Revision != NO_REVISION) {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
215 ds.writeByte(parentMap.get(parent1Revision).toByteArray());
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
216 } else {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
217 ds.writeByte(Nodeid.NULL.toByteArray());
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
218 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
219 if (parent2Revision != NO_REVISION) {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
220 ds.writeByte(parentMap.get(parent2Revision).toByteArray());
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
221 } else {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
222 ds.writeByte(Nodeid.NULL.toByteArray());
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
223 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
224 ds.writeByte(clogMap.get(linkRevision).toByteArray());
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
225 pds.serialize(ds);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
226 } catch (IOException ex) {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
227 // XXX odd to have object with IOException to use where no checked exception is allowed
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
228 throw new HgInvalidControlFileException(ex.getMessage(), ex, null);
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
229 } catch (HgIOException ex) {
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
230 throw new HgInvalidControlFileException(ex, true); // XXX any way to refactor ChunkGenerator not to get checked exception here?
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
231 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
232 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
233 }
1deea2f33218 Push: phase1 - prepare bundle with changes
Artem Tikhomirov <tikhomirov.artem@gmail.com>
parents:
diff changeset
234 }