Switch jgit library to the EDL (3-clause BSD)
[egit/zawir.git] / org.spearce.jgit / src / org / spearce / jgit / transport / WalkRemoteObjectDatabase.java
blob2196fc90285418a7c4879103bca5b8f3fac2f36c
1 /*
2 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
8 * conditions are met:
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
21 * written permission.
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.BufferedReader;
41 import java.io.ByteArrayOutputStream;
42 import java.io.FileNotFoundException;
43 import java.io.IOException;
44 import java.io.InputStream;
45 import java.io.InputStreamReader;
46 import java.util.ArrayList;
47 import java.util.Collection;
49 import org.spearce.jgit.lib.Constants;
50 import org.spearce.jgit.util.NB;
52 /**
53 * Transfers object data through a dumb transport.
54 * <p>
55 * Implementations are responsible for resolving path names relative to the
56 * <code>objects/</code> subdirectory of a single remote Git repository or
57 * nake object database and make the content available as a Java input stream
58 * for reading during fetch. The actual object traversal logic to determine the
59 * names of files to retrieve is handled through the generic, protocol
60 * independent {@link WalkFetchConnection}.
62 abstract class WalkRemoteObjectDatabase {
63 static final String CHARENC = Constants.CHARACTER_ENCODING;
65 static final String INFO_PACKS = "info/packs";
67 static final String INFO_ALTERNATES = "info/alternates";
69 static final String INFO_HTTP_ALTERNATES = "info/http-alternates";
71 /**
72 * Obtain the list of available packs (if any).
73 * <p>
74 * Pack names should be the file name in the packs directory, that is
75 * <code>pack-035760ab452d6eebd123add421f253ce7682355a.pack</code>. Index
76 * names should not be included in the returned collection.
78 * @return list of pack names; null or empty list if none are available.
79 * @throws IOException
80 * The connection is unable to read the remote repository's list
81 * of available pack files.
83 abstract Collection<String> getPackNames() throws IOException;
85 /**
86 * Obtain alternate connections to alternate object databases (if any).
87 * <p>
88 * Alternates are typically read from the file {@link #INFO_ALTERNATES} or
89 * {@link #INFO_HTTP_ALTERNATES}. The content of each line must be resolved
90 * by the implementation and a new database reference should be returned to
91 * represent the additional location.
92 * <p>
93 * Alternates may reuse the same network connection handle, however the
94 * fetch connection will {@link #close()} each created alternate.
96 * @return list of additional object databases the caller could fetch from;
97 * null or empty list if none are configured.
98 * @throws IOException
99 * The connection is unable to read the remote repository's list
100 * of configured alternates.
102 abstract Collection<WalkRemoteObjectDatabase> getAlternates()
103 throws IOException;
106 * Open a single file for reading.
107 * <p>
108 * Implementors should make every attempt possible to ensure
109 * {@link FileNotFoundException} is used when the remote object does not
110 * exist. However when fetching over HTTP some misconfigured servers may
111 * generate a 200 OK status message (rather than a 404 Not Found) with an
112 * HTML formatted message explaining the requested resource does not exist.
113 * Callers such as {@link WalkFetchConnection} are prepared to handle this
114 * by validating the content received, and assuming content that fails to
115 * match its hash is an incorrectly phrased FileNotFoundException.
117 * @param path
118 * location of the file to read, relative to this objects
119 * directory (e.g.
120 * <code>cb/95df6ab7ae9e57571511ef451cf33767c26dd2</code> or
121 * <code>pack/pack-035760ab452d6eebd123add421f253ce7682355a.pack</code>).
122 * @return a stream to read from the file. Never null.
123 * @throws FileNotFoundException
124 * the requested file does not exist at the given location.
125 * @throws IOException
126 * The connection is unable to read the remote's file, and the
127 * failure occurred prior to being able to determine if the file
128 * exists, or after it was determined to exist but before the
129 * stream could be created.
131 abstract FileStream open(String path) throws FileNotFoundException,
132 IOException;
135 * Create a new connection for a discovered alternate object database
136 * <p>
137 * This method is typically called by {@link #readAlternates(String)} when
138 * subclasses us the generic alternate parsing logic for their
139 * implementation of {@link #getAlternates()}.
141 * @param location
142 * the location of the new alternate, relative to the current
143 * object database.
144 * @return a new database connection that can read from the specified
145 * alternate.
146 * @throws IOException
147 * The database connection cannot be established with the
148 * alternate, such as if the alternate location does not
149 * actually exist and the connection's constructor attempts to
150 * verify that.
152 abstract WalkRemoteObjectDatabase openAlternate(String location)
153 throws IOException;
156 * Close any resources used by this connection.
157 * <p>
158 * If the remote repository is contacted by a network socket this method
159 * must close that network socket, disconnecting the two peers. If the
160 * remote repository is actually local (same system) this method must close
161 * any open file handles used to read the "remote" repository.
163 abstract void close();
166 * Open a buffered reader around a file.
167 * <p>
168 * This is shorthand for calling {@link #open(String)} and then wrapping it
169 * in a reader suitable for line oriented files like the alternates list.
171 * @return a stream to read from the file. Never null.
172 * @param path
173 * location of the file to read, relative to this objects
174 * directory (e.g. <code>info/packs</code>).
175 * @throws FileNotFoundException
176 * the requested file does not exist at the given location.
177 * @throws IOException
178 * The connection is unable to read the remote's file, and the
179 * failure occurred prior to being able to determine if the file
180 * exists, or after it was determined to exist but before the
181 * stream could be created.
183 BufferedReader openReader(final String path) throws IOException {
184 return new BufferedReader(new InputStreamReader(open(path).in, CHARENC));
188 * Read a standard Git alternates file to discover other object databases.
189 * <p>
190 * This method is suitable for reading the standard formats of the
191 * alternates file, such as found in <code>objects/info/alternates</code>
192 * or <code>objects/info/http-alternates</code> within a Git repository.
193 * <p>
194 * Alternates appear one per line, with paths expressed relative to this
195 * object database.
197 * @param listPath
198 * location of the alternate file to read, relative to this
199 * object database (e.g. <code>info/alternates</code>).
200 * @return the list of discovered alternates. Empty list if the file exists,
201 * but no entries were discovered.
202 * @throws FileNotFoundException
203 * the requested file does not exist at the given location.
204 * @throws IOException
205 * The connection is unable to read the remote's file, and the
206 * failure occurred prior to being able to determine if the file
207 * exists, or after it was determined to exist but before the
208 * stream could be created.
210 Collection<WalkRemoteObjectDatabase> readAlternates(final String listPath)
211 throws IOException {
212 final BufferedReader br = openReader(listPath);
213 try {
214 final Collection<WalkRemoteObjectDatabase> alts = new ArrayList<WalkRemoteObjectDatabase>();
215 for (;;) {
216 String line = br.readLine();
217 if (line == null)
218 break;
219 if (!line.endsWith("/"))
220 line += "/";
221 alts.add(openAlternate(line));
223 return alts;
224 } finally {
225 br.close();
229 static final class FileStream {
230 final InputStream in;
232 final long length;
235 * Create a new stream of unknown length.
237 * @param i
238 * stream containing the file data. This stream will be
239 * closed by the caller when reading is complete.
241 FileStream(final InputStream i) {
242 in = i;
243 length = -1;
247 * Create a new stream of known length.
249 * @param i
250 * stream containing the file data. This stream will be
251 * closed by the caller when reading is complete.
252 * @param n
253 * total number of bytes available for reading through
254 * <code>i</code>.
256 FileStream(final InputStream i, final long n) {
257 in = i;
258 length = n;
261 byte[] toArray() throws IOException {
262 try {
263 if (length >= 0) {
264 final byte[] r = new byte[(int) length];
265 NB.readFully(in, r, 0, r.length);
266 return r;
269 final ByteArrayOutputStream r = new ByteArrayOutputStream();
270 final byte[] buf = new byte[2048];
271 int n;
272 while ((n = in.read(buf)) >= 0)
273 r.write(buf, 0, n);
274 return r.toByteArray();
275 } finally {
276 in.close();