blob: facb4a54beaa1fc9139a6339f8320bae582c92ee [file] [log] [blame]
/*
* Copyright (C) 2006, 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
* Copyright (C) 2010, 2020, Chris Aniszczyk <caniszczyk@gmail.com> 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.lib;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.util.References;
/**
* Mutable builder to construct an annotated tag recording a project state.
*
* Applications should use this object when they need to manually construct a
* tag and want precise control over its fields.
*
* To read a tag object, construct a {@link org.eclipse.jgit.revwalk.RevWalk}
* and obtain a {@link org.eclipse.jgit.revwalk.RevTag} instance by calling
* {@link org.eclipse.jgit.revwalk.RevWalk#parseTag(AnyObjectId)}.
*/
public class TagBuilder extends ObjectBuilder {
private static final byte[] hobject = Constants.encodeASCII("object"); //$NON-NLS-1$
private static final byte[] htype = Constants.encodeASCII("type"); //$NON-NLS-1$
private static final byte[] htag = Constants.encodeASCII("tag"); //$NON-NLS-1$
private static final byte[] htagger = Constants.encodeASCII("tagger"); //$NON-NLS-1$
private ObjectId object;
private int type = Constants.OBJ_BAD;
private String tag;
/**
* Get the type of object this tag refers to.
*
* @return the type of object this tag refers to.
*/
public int getObjectType() {
return type;
}
/**
* Get the object this tag refers to.
*
* @return the object this tag refers to.
*/
public ObjectId getObjectId() {
return object;
}
/**
* Set the object this tag refers to, and its type.
*
* @param obj
* the object.
* @param objType
* the type of {@code obj}. Must be a valid type code.
*/
public void setObjectId(AnyObjectId obj, int objType) {
object = obj.copy();
type = objType;
}
/**
* Set the object this tag refers to, and infer its type.
*
* @param obj
* the object the tag will refer to.
*/
public void setObjectId(RevObject obj) {
setObjectId(obj, obj.getType());
}
/**
* Get short name of the tag (no {@code refs/tags/} prefix).
*
* @return short name of the tag (no {@code refs/tags/} prefix).
*/
public String getTag() {
return tag;
}
/**
* Set the name of this tag.
*
* @param shortName
* new short name of the tag. This short name should not start
* with {@code refs/} as typically a tag is stored under the
* reference derived from {@code "refs/tags/" + getTag()}.
*/
public void setTag(String shortName) {
this.tag = shortName;
}
/**
* Get creator of this tag.
*
* @return creator of this tag. May be null.
*/
public PersonIdent getTagger() {
return getAuthor();
}
/**
* Set the creator of this tag.
*
* @param taggerIdent
* the creator. May be null.
*/
public void setTagger(PersonIdent taggerIdent) {
setAuthor(taggerIdent);
}
/**
* Format this builder's state as an annotated tag object.
*
* @return this object in the canonical annotated tag format, suitable for
* storage in a repository.
*/
@Override
public byte[] build() throws UnsupportedEncodingException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
try (OutputStreamWriter w = new OutputStreamWriter(os,
getEncoding())) {
os.write(hobject);
os.write(' ');
getObjectId().copyTo(os);
os.write('\n');
os.write(htype);
os.write(' ');
os.write(Constants
.encodeASCII(Constants.typeString(getObjectType())));
os.write('\n');
os.write(htag);
os.write(' ');
w.write(getTag());
w.flush();
os.write('\n');
if (getTagger() != null) {
os.write(htagger);
os.write(' ');
w.write(getTagger().toExternalString());
w.flush();
os.write('\n');
}
writeEncoding(getEncoding(), os);
os.write('\n');
String msg = getMessage();
if (msg != null) {
w.write(msg);
w.flush();
}
GpgSignature signature = getGpgSignature();
if (signature != null) {
if (msg != null && !msg.isEmpty() && !msg.endsWith("\n")) { //$NON-NLS-1$
// If signed, the message *must* end with a linefeed
// character, otherwise signature verification will fail.
// (The signature will have been computed over the payload
// containing the message without LF, but will be verified
// against a payload with the LF.) The signature must start
// on a new line.
throw new JGitInternalException(
JGitText.get().signedTagMessageNoLf);
}
String externalForm = signature.toExternalString();
w.write(externalForm);
w.flush();
if (!externalForm.endsWith("\n")) { //$NON-NLS-1$
os.write('\n');
}
}
} catch (IOException err) {
// This should never occur, the only way to get it above is
// for the ByteArrayOutputStream to throw, but it doesn't.
//
throw new RuntimeException(err);
}
return os.toByteArray();
}
/**
* Format this builder's state as an annotated tag object.
*
* @return this object in the canonical annotated tag format, suitable for
* storage in a repository, or {@code null} if the tag cannot be
* encoded
* @deprecated since 5.11; use {@link #build()} instead
*/
@Deprecated
public byte[] toByteArray() {
try {
return build();
} catch (UnsupportedEncodingException e) {
return null;
}
}
/** {@inheritDoc} */
@SuppressWarnings("nls")
@Override
public String toString() {
StringBuilder r = new StringBuilder();
r.append("Tag");
r.append("={\n");
r.append("object ");
r.append(object != null ? object.name() : "NOT_SET");
r.append("\n");
r.append("type ");
r.append(object != null ? Constants.typeString(type) : "NOT_SET");
r.append("\n");
r.append("tag ");
r.append(tag != null ? tag : "NOT_SET");
r.append("\n");
if (getTagger() != null) {
r.append("tagger ");
r.append(getTagger());
r.append("\n");
}
Charset encoding = getEncoding();
if (!References.isSameObject(encoding, UTF_8)) {
r.append("encoding ");
r.append(encoding.name());
r.append("\n");
}
r.append("\n");
r.append(getMessage() != null ? getMessage() : "");
GpgSignature signature = getGpgSignature();
r.append(signature != null ? signature.toExternalString() : "");
r.append("}");
return r.toString();
}
}