2 * Copyright (C) 2008, Google Inc.
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * - Neither the name of the Git Development Community nor the
19 * names of its contributors may be used to endorse or promote
20 * products derived from this software without specific prior
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 package org
.spearce
.jgit
.transport
;
40 import java
.io
.BufferedOutputStream
;
41 import java
.io
.IOException
;
42 import java
.io
.OutputStream
;
43 import java
.io
.OutputStreamWriter
;
44 import java
.io
.Writer
;
45 import java
.util
.HashSet
;
48 import java
.util
.TreeMap
;
50 import org
.spearce
.jgit
.lib
.AnyObjectId
;
51 import org
.spearce
.jgit
.lib
.Constants
;
52 import org
.spearce
.jgit
.lib
.ObjectId
;
53 import org
.spearce
.jgit
.lib
.PackWriter
;
54 import org
.spearce
.jgit
.lib
.ProgressMonitor
;
55 import org
.spearce
.jgit
.lib
.Ref
;
56 import org
.spearce
.jgit
.lib
.Repository
;
57 import org
.spearce
.jgit
.revwalk
.RevCommit
;
60 * Creates a Git bundle file, for sneaker-net transport to another system.
62 * Bundles generated by this class can be later read in from a file URI using
63 * the bundle transport, or from an application controlled buffer by the more
64 * generic {@link TransportBundleStream}.
66 * Applications creating bundles need to call one or more <code>include</code>
67 * calls to reflect which objects should be available as refs in the bundle for
68 * the other side to fetch. At least one include is required to create a valid
69 * bundle file, and duplicate names are not permitted.
71 * Optional <code>assume</code> calls can be made to declare commits which the
72 * recipient must have in order to fetch from the bundle file. Objects reachable
73 * from these assumed commits can be used as delta bases in order to reduce the
74 * overall bundle size.
76 public class BundleWriter
{
77 private final PackWriter packWriter
;
79 private final Map
<String
, ObjectId
> include
;
81 private final Set
<RevCommit
> assume
;
84 * Create a writer for a bundle.
87 * repository where objects are stored.
89 * operations progress monitor.
91 public BundleWriter(final Repository repo
, final ProgressMonitor monitor
) {
92 packWriter
= new PackWriter(repo
, monitor
);
93 include
= new TreeMap
<String
, ObjectId
>();
94 assume
= new HashSet
<RevCommit
>();
98 * Include an object (and everything reachable from it) in the bundle.
101 * name the recipient can discover this object as from the
102 * bundle's list of advertised refs . The name must be a valid
103 * ref format and must not have already been included in this
106 * object to pack. Multiple refs may point to the same object.
108 public void include(final String name
, final AnyObjectId id
) {
109 if (!Repository
.isValidRefName(name
))
110 throw new IllegalArgumentException("Invalid ref name: " + name
);
111 if (include
.containsKey(name
))
112 throw new IllegalStateException("Duplicate ref: " + name
);
113 include
.put(name
, id
.toObjectId());
117 * Include a single ref (a name/object pair) in the bundle.
119 * This is a utility function for:
120 * <code>include(r.getName(), r.getObjectId())</code>.
123 * the ref to include.
125 public void include(final Ref r
) {
126 include(r
.getName(), r
.getObjectId());
130 * Assume a commit is available on the recipient's side.
132 * In order to fetch from a bundle the recipient must have any assumed
133 * commit. Each assumed commit is explicitly recorded in the bundle header
134 * to permit the recipient to validate it has these objects.
137 * the commit to assume being available. This commit should be
138 * parsed and not disposed in order to maximize the amount of
139 * debugging information available in the bundle stream.
141 public void assume(final RevCommit c
) {
147 * Generate and write the bundle to the output stream.
149 * This method can only be called once per BundleWriter instance.
152 * the stream the bundle is written to. If the stream is not
153 * buffered it will be buffered by the writer. Caller is
154 * responsible for closing the stream.
155 * @throws IOException
156 * an error occurred reading a local object's data to include in
157 * the bundle, or writing compressed object data to the output
160 public void writeBundle(OutputStream os
) throws IOException
{
161 if (!(os
instanceof BufferedOutputStream
))
162 os
= new BufferedOutputStream(os
);
164 final HashSet
<ObjectId
> inc
= new HashSet
<ObjectId
>();
165 final HashSet
<ObjectId
> exc
= new HashSet
<ObjectId
>();
166 inc
.addAll(include
.values());
167 for (final RevCommit r
: assume
)
169 packWriter
.preparePack(inc
, exc
, exc
.size() > 0, true);
171 final Writer w
= new OutputStreamWriter(os
, Constants
.CHARSET
);
172 w
.write(TransportBundle
.V2_BUNDLE_SIGNATURE
);
175 final char[] tmp
= new char[Constants
.OBJECT_ID_LENGTH
* 2];
176 for (final RevCommit a
: assume
) {
179 if (a
.getRawBuffer() != null) {
181 w
.write(a
.getShortMessage());
185 for (final Map
.Entry
<String
, ObjectId
> e
: include
.entrySet()) {
186 e
.getValue().copyTo(tmp
, w
);
194 packWriter
.writePack(os
);