Reduce multi-level buffered streams in transport code
[jgit/MarioXXX.git] / org.eclipse.jgit / src / org / eclipse / jgit / transport / BundleWriter.java
blob7b0a5eec4545510ee63c965be34302f22ffe17ca
1 /*
2 * Copyright (C) 2008-2010, Google Inc.
3 * and other copyright owners as documented in the project's IP log.
5 * This program and the accompanying materials are made available
6 * under the terms of the Eclipse Distribution License v1.0 which
7 * accompanies this distribution, is reproduced below, and is
8 * available at http://www.eclipse.org/org/documents/edl-v10.php
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
14 * conditions are met:
16 * - Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
19 * - Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials provided
22 * with the distribution.
24 * - Neither the name of the Eclipse Foundation, Inc. nor the
25 * names of its contributors may be used to endorse or promote
26 * products derived from this software without specific prior
27 * written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 package org.eclipse.jgit.transport;
46 import java.io.IOException;
47 import java.io.OutputStream;
48 import java.io.OutputStreamWriter;
49 import java.io.Writer;
50 import java.util.HashSet;
51 import java.util.Map;
52 import java.util.Set;
53 import java.util.TreeMap;
55 import org.eclipse.jgit.lib.AnyObjectId;
56 import org.eclipse.jgit.lib.Constants;
57 import org.eclipse.jgit.lib.ObjectId;
58 import org.eclipse.jgit.lib.PackWriter;
59 import org.eclipse.jgit.lib.ProgressMonitor;
60 import org.eclipse.jgit.lib.Ref;
61 import org.eclipse.jgit.lib.Repository;
62 import org.eclipse.jgit.revwalk.RevCommit;
64 /**
65 * Creates a Git bundle file, for sneaker-net transport to another system.
66 * <p>
67 * Bundles generated by this class can be later read in from a file URI using
68 * the bundle transport, or from an application controlled buffer by the more
69 * generic {@link TransportBundleStream}.
70 * <p>
71 * Applications creating bundles need to call one or more <code>include</code>
72 * calls to reflect which objects should be available as refs in the bundle for
73 * the other side to fetch. At least one include is required to create a valid
74 * bundle file, and duplicate names are not permitted.
75 * <p>
76 * Optional <code>assume</code> calls can be made to declare commits which the
77 * recipient must have in order to fetch from the bundle file. Objects reachable
78 * from these assumed commits can be used as delta bases in order to reduce the
79 * overall bundle size.
81 public class BundleWriter {
82 private final PackWriter packWriter;
84 private final Map<String, ObjectId> include;
86 private final Set<RevCommit> assume;
88 /**
89 * Create a writer for a bundle.
91 * @param repo
92 * repository where objects are stored.
93 * @param monitor
94 * operations progress monitor.
96 public BundleWriter(final Repository repo, final ProgressMonitor monitor) {
97 packWriter = new PackWriter(repo, monitor);
98 include = new TreeMap<String, ObjectId>();
99 assume = new HashSet<RevCommit>();
103 * Include an object (and everything reachable from it) in the bundle.
105 * @param name
106 * name the recipient can discover this object as from the
107 * bundle's list of advertised refs . The name must be a valid
108 * ref format and must not have already been included in this
109 * bundle writer.
110 * @param id
111 * object to pack. Multiple refs may point to the same object.
113 public void include(final String name, final AnyObjectId id) {
114 if (!Repository.isValidRefName(name))
115 throw new IllegalArgumentException("Invalid ref name: " + name);
116 if (include.containsKey(name))
117 throw new IllegalStateException("Duplicate ref: " + name);
118 include.put(name, id.toObjectId());
122 * Include a single ref (a name/object pair) in the bundle.
123 * <p>
124 * This is a utility function for:
125 * <code>include(r.getName(), r.getObjectId())</code>.
127 * @param r
128 * the ref to include.
130 public void include(final Ref r) {
131 include(r.getName(), r.getObjectId());
135 * Assume a commit is available on the recipient's side.
136 * <p>
137 * In order to fetch from a bundle the recipient must have any assumed
138 * commit. Each assumed commit is explicitly recorded in the bundle header
139 * to permit the recipient to validate it has these objects.
141 * @param c
142 * the commit to assume being available. This commit should be
143 * parsed and not disposed in order to maximize the amount of
144 * debugging information available in the bundle stream.
146 public void assume(final RevCommit c) {
147 if (c != null)
148 assume.add(c);
152 * Generate and write the bundle to the output stream.
153 * <p>
154 * This method can only be called once per BundleWriter instance.
156 * @param os
157 * the stream the bundle is written to. The stream should be
158 * buffered by the caller. The caller is responsible for closing
159 * the stream.
160 * @throws IOException
161 * an error occurred reading a local object's data to include in
162 * the bundle, or writing compressed object data to the output
163 * stream.
165 public void writeBundle(OutputStream os) throws IOException {
166 final HashSet<ObjectId> inc = new HashSet<ObjectId>();
167 final HashSet<ObjectId> exc = new HashSet<ObjectId>();
168 inc.addAll(include.values());
169 for (final RevCommit r : assume)
170 exc.add(r.getId());
171 packWriter.setThin(exc.size() > 0);
172 packWriter.preparePack(inc, exc);
174 final Writer w = new OutputStreamWriter(os, Constants.CHARSET);
175 w.write(TransportBundle.V2_BUNDLE_SIGNATURE);
176 w.write('\n');
178 final char[] tmp = new char[Constants.OBJECT_ID_STRING_LENGTH];
179 for (final RevCommit a : assume) {
180 w.write('-');
181 a.copyTo(tmp, w);
182 if (a.getRawBuffer() != null) {
183 w.write(' ');
184 w.write(a.getShortMessage());
186 w.write('\n');
188 for (final Map.Entry<String, ObjectId> e : include.entrySet()) {
189 e.getValue().copyTo(tmp, w);
190 w.write(' ');
191 w.write(e.getKey());
192 w.write('\n');
195 w.write('\n');
196 w.flush();
197 packWriter.writePack(os);