blob: 94a4e9c129629a300637ede6e695e7f5d5929b16 [file] [log] [blame]
/*
* Copyright (C) 2023, Google LLC and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
* https://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
package org.eclipse.jgit.internal.storage.file;
import static org.eclipse.jgit.internal.storage.file.PackReverseIndex.VERSION_1;
import java.io.BufferedOutputStream;
import java.io.DataOutput;
import java.io.IOException;
import java.io.OutputStream;
import java.security.DigestOutputStream;
import java.text.MessageFormat;
import java.util.List;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.transport.PackedObjectInfo;
/**
* Writes reverse index files conforming to the requested version.
* <p>
* The reverse index file format is specified at
* https://git-scm.com/docs/pack-format#_pack_rev_files_have_the_format.
*/
public abstract class PackReverseIndexWriter {
/**
* Stream to write contents to while maintaining a checksum.
*/
protected final DigestOutputStream out;
/**
* Stream to write primitive type contents to while maintaining a checksum.
*/
protected final DataOutput dataOutput;
private static final int DEFAULT_VERSION = VERSION_1;
/**
* Construct the components of a PackReverseIndexWriter that are shared
* between subclasses.
*
* @param dst
* the OutputStream that the instance will write contents to
*/
protected PackReverseIndexWriter(OutputStream dst) {
out = new DigestOutputStream(
dst instanceof BufferedOutputStream ? dst
: new BufferedOutputStream(dst),
Constants.newMessageDigest());
dataOutput = new SimpleDataOutput(out);
}
/**
* Create a writer instance for the default file format version.
*
* @param dst
* the OutputStream that contents will be written to
* @return the new writer instance
*/
public static PackReverseIndexWriter createWriter(OutputStream dst) {
return createWriter(dst, DEFAULT_VERSION);
}
/**
* Create a writer instance for the specified file format version.
*
* @param dst
* the OutputStream that contents will be written to
* @param version
* the reverse index format version to write contents as
* @return the new writer instance
*/
public static PackReverseIndexWriter createWriter(OutputStream dst,
int version) {
if (version == VERSION_1) {
return new PackReverseIndexWriterV1(dst);
}
throw new IllegalArgumentException(MessageFormat.format(
JGitText.get().unsupportedPackReverseIndexVersion,
Integer.toString(version)));
}
/**
* Write the contents of a reverse index file for the given objects.
*
* @param objectsByIndexPos
* the objects whose forward index file positions should be
* written, sorted by forward index file position (currently SHA1
* ordering)
* @param packChecksum
* the checksum of the corresponding pack file
* @throws IOException
* if writing the output fails
*/
public void write(
List<? extends PackedObjectInfo> objectsByIndexPos,
byte[] packChecksum) throws IOException {
writeHeader();
writeBody(objectsByIndexPos);
writeFooter(packChecksum);
out.flush();
}
/**
* Write the header of a reverse index file, usually the magic bytes and the
* file format version.
*
* @throws IOException
* if writing the output fails
*/
protected abstract void writeHeader() throws IOException;
/**
* Write the body of a reverse index file, usually the forward index
* positions of the given objects, sorted by those objects' pack file
* offsets.
*
* @param objectsSortedByIndexPosition
* the objects whose forward index file positions should be
* written, sorted by forward index file position; not modified
* during method
* @throws IOException
* if writing the output fails
*/
protected abstract void writeBody(
List<? extends PackedObjectInfo> objectsSortedByIndexPosition)
throws IOException;
private void writeFooter(byte[] packChecksum) throws IOException {
out.write(packChecksum);
byte[] selfChecksum = out.getMessageDigest().digest();
out.write(selfChecksum);
}
}