annotate src/org/tmatesoft/hg/internal/BundleGenerator.java @ 698:822f3a83ff57

in, out and clone tests pass for ssh repositories. Infrastructure to decouple HgRemoteRepository from specific Connector implementation
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Tue, 06 Aug 2013 21:18:33 +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 }