View Javadoc
1   /*
2    * Copyright (C) 2017, Google Inc. and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  
11  package org.eclipse.jgit.internal.storage.reftable;
12  
13  import static org.eclipse.jgit.lib.RefDatabase.MAX_SYMBOLIC_REF_DEPTH;
14  
15  import java.io.ByteArrayOutputStream;
16  import java.io.IOException;
17  import java.util.Collection;
18  
19  import org.eclipse.jgit.annotations.Nullable;
20  import org.eclipse.jgit.internal.storage.io.BlockSource;
21  import org.eclipse.jgit.lib.AnyObjectId;
22  import org.eclipse.jgit.lib.Ref;
23  import org.eclipse.jgit.lib.SymbolicRef;
24  
25  /**
26   * Abstract table of references.
27   */
28  public abstract class Reftable {
29  	/**
30  	 * References to convert into a reftable
31  	 *
32  	 * @param refs
33  	 *            references to convert into a reftable; may be empty.
34  	 * @return a reader for the supplied references.
35  	 */
36  	public static Reftable from(Collection<Ref> refs) {
37  		try {
38  			ReftableConfig cfg = new ReftableConfig();
39  			cfg.setIndexObjects(false);
40  			cfg.setAlignBlocks(false);
41  			ByteArrayOutputStream buf = new ByteArrayOutputStream();
42  			new ReftableWriter(buf)
43  				.setConfig(cfg)
44  				.begin()
45  				.sortAndWriteRefs(refs)
46  				.finish();
47  			return new ReftableReader(BlockSource.from(buf.toByteArray()));
48  		} catch (IOException e) {
49  			throw new RuntimeException(e);
50  		}
51  	}
52  
53  	/** {@code true} if deletions should be included in results. */
54  	protected boolean includeDeletes;
55  
56  	/**
57  	 * Whether deleted references will be returned.
58  	 *
59  	 * @param deletes
60  	 *            if {@code true} deleted references will be returned. If
61  	 *            {@code false} (default behavior), deleted references will be
62  	 *            skipped, and not returned.
63  	 */
64  	public void setIncludeDeletes(boolean deletes) {
65  		includeDeletes = deletes;
66  	}
67  
68  	/**
69  	 * Get the maximum update index for ref entries that appear in this
70  	 * reftable.
71  	 *
72  	 * @return the maximum update index for ref entries that appear in this
73  	 *         reftable.
74  	 * @throws java.io.IOException
75  	 *             file cannot be read.
76  	 */
77  	public abstract long maxUpdateIndex() throws IOException;
78  
79  	/**
80  	 * Get the minimum update index for ref entries that appear in this
81  	 * reftable.
82  	 *
83  	 * @return the minimum update index for ref entries that appear in this
84  	 *         reftable.
85  	 * @throws java.io.IOException
86  	 *             file cannot be read.
87  	 */
88  	public abstract long minUpdateIndex() throws IOException;
89  
90  	/**
91  	 * Seek to the first reference, to iterate in order.
92  	 *
93  	 * @return cursor to iterate.
94  	 * @throws java.io.IOException
95  	 *             if references cannot be read.
96  	 */
97  	public abstract RefCursor allRefs() throws IOException;
98  
99  	/**
100 	 * Seek to a reference.
101 	 * <p>
102 	 * This method will seek to the reference {@code refName}. If present, the
103 	 * returned cursor will iterate exactly one entry. If not found, an empty
104 	 * cursor is returned.
105 	 *
106 	 * @param refName
107 	 *            reference name.
108 	 * @return cursor to iterate; empty cursor if no references match.
109 	 * @throws java.io.IOException
110 	 *             if references cannot be read.
111 	 */
112 	public abstract RefCursor seekRef(String refName) throws IOException;
113 
114 	/**
115 	 * Seek references with prefix.
116 	 * <p>
117 	 * The method will seek all the references starting with {@code prefix} as a
118 	 * prefix. If no references start with this prefix, an empty cursor is
119 	 * returned.
120 	 *
121 	 * @param prefix
122 	 *            prefix to find.
123 	 * @return cursor to iterate; empty cursor if no references match.
124 	 * @throws java.io.IOException
125 	 *             if references cannot be read.
126 	 */
127 	public abstract RefCursor seekRefsWithPrefix(String prefix) throws IOException;
128 
129 	/**
130 	 * Match references pointing to a specific object.
131 	 *
132 	 * @param id
133 	 *            object to find.
134 	 * @return cursor to iterate; empty cursor if no references match.
135 	 * @throws java.io.IOException
136 	 *             if references cannot be read.
137 	 */
138 	public abstract RefCursor byObjectId(AnyObjectId id) throws IOException;
139 
140 	/**
141 	 * @return whether this reftable can do a fast SHA1 => ref lookup.
142 	 * @throws IOException on I/O problems.
143 	 */
144 	public abstract boolean hasObjectMap() throws IOException;
145 
146 	/**
147 	 * Seek reader to read log records.
148 	 *
149 	 * @return cursor to iterate; empty cursor if no logs are present.
150 	 * @throws java.io.IOException
151 	 *             if logs cannot be read.
152 	 */
153 	public abstract LogCursor allLogs() throws IOException;
154 
155 	/**
156 	 * Read a single reference's log.
157 	 *
158 	 * @param refName
159 	 *            exact name of the reference whose log to read.
160 	 * @return cursor to iterate; empty cursor if no logs match.
161 	 * @throws java.io.IOException
162 	 *             if logs cannot be read.
163 	 */
164 	public LogCursor seekLog(String refName) throws IOException {
165 		return seekLog(refName, Long.MAX_VALUE);
166 	}
167 
168 	/**
169 	 * Seek to an update index in a reference's log.
170 	 *
171 	 * @param refName
172 	 *            exact name of the reference whose log to read.
173 	 * @param updateIndex
174 	 *            most recent index to return first in the log cursor. Log
175 	 *            records at or before {@code updateIndex} will be returned.
176 	 * @return cursor to iterate; empty cursor if no logs match.
177 	 * @throws java.io.IOException
178 	 *             if logs cannot be read.
179 	 */
180 	public abstract LogCursor seekLog(String refName, long updateIndex)
181 			throws IOException;
182 
183 	/**
184 	 * Lookup a reference, or null if not found.
185 	 *
186 	 * @param refName
187 	 *            reference name to find.
188 	 * @return the reference, or {@code null} if not found.
189 	 * @throws java.io.IOException
190 	 *             if references cannot be read.
191 	 */
192 	@Nullable
193 	public Ref exactRef(String refName) throws IOException {
194 		try (RefCursor rc = seekRef(refName)) {
195 			return rc.next() ? rc.getRef() : null;
196 		}
197 	}
198 
199 	/**
200 	 * Test if a reference exists.
201 	 *
202 	 * @param refName
203 	 *            reference name or subtree to find.
204 	 * @return {@code true} if the reference exists.
205 	 * @throws java.io.IOException
206 	 *             if references cannot be read.
207 	 */
208 	public boolean hasRef(String refName) throws IOException {
209 		try (RefCursor rc = seekRef(refName)) {
210 			return rc.next();
211 		}
212 	}
213 
214 	/**
215 	 * Test if any reference starts with {@code prefix} as a prefix.
216 	 *
217 	 * @param prefix
218 	 *            prefix to find.
219 	 * @return {@code true} if at least one reference exists with prefix.
220 	 * @throws java.io.IOException
221 	 *             if references cannot be read.
222 	 */
223 	public boolean hasRefsWithPrefix(String prefix) throws IOException {
224 		try (RefCursor rc = seekRefsWithPrefix(prefix)) {
225 			return rc.next();
226 		}
227 	}
228 
229 	/**
230 	 * Test if any reference directly refers to the object.
231 	 *
232 	 * @param id
233 	 *            ObjectId to find.
234 	 * @return {@code true} if any reference exists directly referencing
235 	 *         {@code id}, or a annotated tag that peels to {@code id}.
236 	 * @throws java.io.IOException
237 	 *             if references cannot be read.
238 	 */
239 	public boolean hasId(AnyObjectId id) throws IOException {
240 		try (RefCursor rc = byObjectId(id)) {
241 			return rc.next();
242 		}
243 	}
244 
245 	/**
246 	 * Resolve a symbolic reference to populate its value.
247 	 *
248 	 * @param symref
249 	 *            reference to resolve.
250 	 * @return resolved {@code symref}, or {@code null}.
251 	 * @throws java.io.IOException
252 	 *             if references cannot be read.
253 	 */
254 	@Nullable
255 	public Refref="../../../../../../org/eclipse/jgit/lib/Ref.html#Ref">Ref resolve(Ref symref) throws IOException {
256 		return resolve(symref, 0);
257 	}
258 
259 	private Refref="../../../../../../org/eclipse/jgit/lib/Ref.html#Ref">Ref resolve(Ref ref, int depth) throws IOException {
260 		if (!ref.isSymbolic()) {
261 			return ref;
262 		}
263 
264 		Ref dst = ref.getTarget();
265 		if (MAX_SYMBOLIC_REF_DEPTH <= depth) {
266 			return null; // claim it doesn't exist
267 		}
268 
269 		dst = exactRef(dst.getName());
270 		if (dst == null) {
271 			return ref;
272 		}
273 
274 		dst = resolve(dst, depth + 1);
275 		if (dst == null) {
276 			return null; // claim it doesn't exist
277 		}
278 		return new SymbolicRef(ref.getName(), dst, ref.getUpdateIndex());
279 	}
280 }