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
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
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
;
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
;
65 * Creates a Git bundle file, for sneaker-net transport to another system.
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}.
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.
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
;
89 * Create a writer for a bundle.
92 * repository where objects are stored.
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.
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
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.
124 * This is a utility function for:
125 * <code>include(r.getName(), r.getObjectId())</code>.
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.
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.
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
) {
152 * Generate and write the bundle to the output stream.
154 * This method can only be called once per BundleWriter instance.
157 * the stream the bundle is written to. The stream should be
158 * buffered by the caller. The caller is responsible for closing
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
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
)
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
);
178 final char[] tmp
= new char[Constants
.OBJECT_ID_STRING_LENGTH
];
179 for (final RevCommit a
: assume
) {
182 if (a
.getRawBuffer() != null) {
184 w
.write(a
.getShortMessage());
188 for (final Map
.Entry
<String
, ObjectId
> e
: include
.entrySet()) {
189 e
.getValue().copyTo(tmp
, w
);
197 packWriter
.writePack(os
);