Documentation. Added JavaDoc comments.
| | |
| | |
|
| | | import org.eclipse.jgit.revwalk.RevCommit;
|
| | |
|
| | | /**
|
| | | * AnnotatedLine is a serializable model class that represents a the most recent
|
| | | * author, date, and commit id of a line in a source file.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class AnnotatedLine implements Serializable {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
| | |
|
| | | import java.io.Serializable;
|
| | |
|
| | | /**
|
| | | * GitNote is a serializable model class that represents a git note. This class
|
| | | * retains an instance of the RefModel which contains the commit in which this
|
| | | * git note was created.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class GitNote implements Serializable {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | public String content;
|
| | | public RefModel notesRef;
|
| | | public final String content;
|
| | | public final RefModel notesRef;
|
| | |
|
| | | public GitNote(RefModel notesRef, String text) {
|
| | | this.notesRef = notesRef;
|
| | |
| | |
|
| | | import java.io.Serializable;
|
| | |
|
| | | /**
|
| | | * Metric is a serializable model class that encapsulates metrics for some given
|
| | | * type.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class Metric implements Serializable {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | public String name;
|
| | | public final String name;
|
| | | public double count;
|
| | | public double tag;
|
| | | public int duration;
|
| | |
| | | import org.eclipse.jgit.diff.DiffEntry.ChangeType;
|
| | | import org.eclipse.jgit.lib.FileMode;
|
| | |
|
| | | /**
|
| | | * PathModel is a serializable model class that represents a file or a folder,
|
| | | * including all its metadata and associated commit id.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class PathModel implements Serializable, Comparable<PathModel> {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
| | | return 1;
|
| | | }
|
| | |
|
| | | /**
|
| | | * PathChangeModel is a serializable class that represents a file changed in
|
| | | * a commit.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public static class PathChangeModel extends PathModel {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
| | | import org.eclipse.jgit.revwalk.RevObject;
|
| | | import org.eclipse.jgit.revwalk.RevTag;
|
| | |
|
| | | /**
|
| | | * RefModel is a serializable model class that represents a tag or branch and
|
| | | * includes the referenced object.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class RefModel implements Serializable, Comparable<RefModel> {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
| | |
|
| | | import com.gitblit.Constants.AccessRestrictionType;
|
| | |
|
| | | /**
|
| | | * RepositoryModel is a serializable model class that represents a Gitblit
|
| | | * repository including its configuration settings and access restriction.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class RepositoryModel implements Serializable {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
| | | import java.util.Date;
|
| | | import java.util.List;
|
| | |
|
| | | /**
|
| | | * TicketModel is a serializable model class that represents a Ticgit ticket.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class TicketModel implements Serializable, Comparable<TicketModel> {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | @Override
|
| | | public int hashCode() {
|
| | | return id.hashCode();
|
| | | }
|
| | |
|
| | | @Override
|
| | | public boolean equals(Object o) {
|
| | | if (o instanceof TicketModel) {
|
| | | TicketModel other = (TicketModel) o;
|
| | | return id.equals(other.id);
|
| | | }
|
| | | return super.equals(o);
|
| | | }
|
| | |
|
| | | @Override
|
| | | public int compareTo(TicketModel o) {
|
| | | return date.compareTo(o.date);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Comment is a serializable model class that represents a Ticgit ticket
|
| | | * comment.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public static class Comment implements Serializable, Comparable<Comment> {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
| | | public int compareTo(Comment o) {
|
| | | return date.compareTo(o.date);
|
| | | }
|
| | | }
|
| | |
|
| | | @Override
|
| | | public int hashCode() {
|
| | | return id.hashCode();
|
| | | }
|
| | |
|
| | | @Override
|
| | | public boolean equals(Object o) {
|
| | | if (o instanceof TicketModel) {
|
| | | TicketModel other = (TicketModel) o;
|
| | | return id.equals(other.id);
|
| | | }
|
| | | return super.equals(o);
|
| | | }
|
| | |
|
| | | @Override
|
| | | public int compareTo(TicketModel o) {
|
| | | return date.compareTo(o.date);
|
| | | }
|
| | | }
|
| | |
| | | import java.util.ArrayList;
|
| | | import java.util.List;
|
| | |
|
| | | /**
|
| | | * UserModel is a serializable model class that represents a user and the user's
|
| | | * restricted repository memberships. Instances of UserModels are also used as
|
| | | * servlet user principals.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class UserModel implements Principal, Serializable {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
| | | import java.text.Format; |
| | | import java.text.ParsePosition; |
| | | |
| | | /** |
| | | * ByteFormat is a formatter which takes numbers and returns filesizes in bytes, |
| | | * kilobytes, megabytes, or gigabytes. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | public class ByteFormat extends Format { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | |
| | | import org.eclipse.jgit.revwalk.RevCommit;
|
| | | import org.eclipse.jgit.revwalk.RevTree;
|
| | | import org.eclipse.jgit.revwalk.RevWalk;
|
| | | import org.eclipse.jgit.treewalk.TreeWalk;
|
| | | import org.eclipse.jgit.treewalk.filter.TreeFilter;
|
| | | import org.slf4j.Logger;
|
| | | import org.slf4j.LoggerFactory;
|
| | |
|
| | | import com.gitblit.models.AnnotatedLine;
|
| | |
|
| | | /**
|
| | | * DiffUtils is a class of utility methods related to diff, patch, and blame.
|
| | | * |
| | | * The diff methods support pluggable diff output types like Gitblit, Gitweb,
|
| | | * and Plain.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class DiffUtils {
|
| | |
|
| | | private static final Logger LOGGER = LoggerFactory.getLogger(DiffUtils.class);
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | public static String getCommitDiff(Repository r, RevCommit commit, DiffOutputType outputType) {
|
| | | return getDiff(r, null, commit, null, outputType);
|
| | | /**
|
| | | * Returns the complete diff of the specified commit compared to its primary
|
| | | * parent.
|
| | | * |
| | | * @param repository
|
| | | * @param commit
|
| | | * @param outputType
|
| | | * @return the diff as a string
|
| | | */
|
| | | public static String getCommitDiff(Repository repository, RevCommit commit,
|
| | | DiffOutputType outputType) {
|
| | | return getDiff(repository, null, commit, null, outputType);
|
| | | }
|
| | |
|
| | | public static String getDiff(Repository r, RevCommit commit, String path,
|
| | | /**
|
| | | * Returns the diff for the specified file or folder from the specified
|
| | | * commit compared to its primary parent.
|
| | | * |
| | | * @param repository
|
| | | * @param commit
|
| | | * @param path
|
| | | * @param outputType
|
| | | * @return the diff as a string
|
| | | */
|
| | | public static String getDiff(Repository repository, RevCommit commit, String path,
|
| | | DiffOutputType outputType) {
|
| | | return getDiff(r, null, commit, path, outputType);
|
| | | return getDiff(repository, null, commit, path, outputType);
|
| | | }
|
| | |
|
| | | public static String getDiff(Repository r, RevCommit baseCommit, RevCommit commit,
|
| | | /**
|
| | | * Returns the complete diff between the two specified commits.
|
| | | * |
| | | * @param repository
|
| | | * @param baseCommit
|
| | | * @param commit
|
| | | * @param outputType
|
| | | * @return the diff as a string
|
| | | */
|
| | | public static String getDiff(Repository repository, RevCommit baseCommit, RevCommit commit,
|
| | | DiffOutputType outputType) {
|
| | | return getDiff(r, baseCommit, commit, null, outputType);
|
| | | return getDiff(repository, baseCommit, commit, null, outputType);
|
| | | }
|
| | |
|
| | | public static String getDiff(Repository r, RevCommit baseCommit, RevCommit commit, String path,
|
| | | DiffOutputType outputType) {
|
| | | /**
|
| | | * Returns the diff between two commits for the specified file.
|
| | | * |
| | | * @param repository
|
| | | * @param baseCommit
|
| | | * if base commit is null the diff is to the primary parent of
|
| | | * the commit.
|
| | | * @param commit
|
| | | * @param path
|
| | | * if the path is specified, the diff is restricted to that file
|
| | | * or folder. if unspecified, the diff is for the entire commit.
|
| | | * @param outputType
|
| | | * @return the diff as a string
|
| | | */
|
| | | public static String getDiff(Repository repository, RevCommit baseCommit, RevCommit commit,
|
| | | String path, DiffOutputType outputType) {
|
| | | String diff = null;
|
| | | try {
|
| | | RevTree baseTree;
|
| | | if (baseCommit == null) {
|
| | | final RevWalk rw = new RevWalk(r);
|
| | | RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
|
| | | rw.dispose();
|
| | | baseTree = parent.getTree();
|
| | | } else {
|
| | | baseTree = baseCommit.getTree();
|
| | | }
|
| | |
|
| | | RevTree commitTree = commit.getTree();
|
| | |
|
| | | final TreeWalk walk = new TreeWalk(r);
|
| | | walk.reset();
|
| | | walk.setRecursive(true);
|
| | | walk.addTree(baseTree);
|
| | | walk.addTree(commitTree);
|
| | | walk.setFilter(TreeFilter.ANY_DIFF);
|
| | |
|
| | | final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
| | | RawTextComparator cmp = RawTextComparator.DEFAULT;
|
| | | DiffFormatter df;
|
| | |
| | | df = new DiffFormatter(os);
|
| | | break;
|
| | | }
|
| | | df.setRepository(r);
|
| | | df.setRepository(repository);
|
| | | df.setDiffComparator(cmp);
|
| | | df.setDetectRenames(true);
|
| | |
|
| | | RevTree commitTree = commit.getTree();
|
| | | RevTree baseTree;
|
| | | if (baseCommit == null) {
|
| | | final RevWalk rw = new RevWalk(repository);
|
| | | RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
|
| | | rw.dispose();
|
| | | baseTree = parent.getTree();
|
| | | } else {
|
| | | baseTree = baseCommit.getTree();
|
| | | }
|
| | |
|
| | | List<DiffEntry> diffEntries = df.scan(baseTree, commitTree);
|
| | | if (path != null && path.length() > 0) {
|
| | | for (DiffEntry diffEntry : diffEntries) {
|
| | |
| | | return diff;
|
| | | }
|
| | |
|
| | | public static String getCommitPatch(Repository r, RevCommit baseCommit, RevCommit commit,
|
| | | String path) {
|
| | | /**
|
| | | * Returns the diff between the two commits for the specified file or folder
|
| | | * formatted as a patch.
|
| | | * |
| | | * @param repository
|
| | | * @param baseCommit
|
| | | * if base commit is unspecified, the patch is generated against
|
| | | * the primary parent of the specified commit.
|
| | | * @param commit
|
| | | * @param path
|
| | | * if path is specified, the patch is generated only for the
|
| | | * specified file or folder. if unspecified, the patch is
|
| | | * generated for the entire diff between the two commits.
|
| | | * @return patch as a string
|
| | | */
|
| | | public static String getCommitPatch(Repository repository, RevCommit baseCommit,
|
| | | RevCommit commit, String path) {
|
| | | String diff = null;
|
| | | try {
|
| | | final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
| | | RawTextComparator cmp = RawTextComparator.DEFAULT;
|
| | | PatchFormatter df = new PatchFormatter(os);
|
| | | df.setRepository(repository);
|
| | | df.setDiffComparator(cmp);
|
| | | df.setDetectRenames(true);
|
| | |
|
| | | RevTree commitTree = commit.getTree();
|
| | | RevTree baseTree;
|
| | | if (baseCommit == null) {
|
| | | final RevWalk rw = new RevWalk(r);
|
| | | final RevWalk rw = new RevWalk(repository);
|
| | | RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
|
| | | baseTree = parent.getTree();
|
| | | } else {
|
| | | baseTree = baseCommit.getTree();
|
| | | }
|
| | | RevTree commitTree = commit.getTree();
|
| | |
|
| | | final TreeWalk walk = new TreeWalk(r);
|
| | | walk.reset();
|
| | | walk.setRecursive(true);
|
| | | walk.addTree(baseTree);
|
| | | walk.addTree(commitTree);
|
| | | walk.setFilter(TreeFilter.ANY_DIFF);
|
| | |
|
| | | final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
| | | RawTextComparator cmp = RawTextComparator.DEFAULT;
|
| | | PatchFormatter df = new PatchFormatter(os);
|
| | | df.setRepository(r);
|
| | | df.setDiffComparator(cmp);
|
| | | df.setDetectRenames(true);
|
| | | List<DiffEntry> diffEntries = df.scan(baseTree, commitTree);
|
| | | if (path != null && path.length() > 0) {
|
| | | for (DiffEntry diffEntry : diffEntries) {
|
| | |
| | | return diff;
|
| | | }
|
| | |
|
| | | public static List<AnnotatedLine> blame(Repository r, String blobPath, String objectId) {
|
| | | /**
|
| | | * Returns the list of lines in the specified source file annotated with the
|
| | | * source commit metadata.
|
| | | * |
| | | * @param repository
|
| | | * @param blobPath
|
| | | * @param objectId
|
| | | * @return list of annotated lines
|
| | | */
|
| | | public static List<AnnotatedLine> blame(Repository repository, String blobPath, String objectId) {
|
| | | List<AnnotatedLine> lines = new ArrayList<AnnotatedLine>();
|
| | | try {
|
| | | if (StringUtils.isEmpty(objectId)) {
|
| | | objectId = Constants.HEAD;
|
| | | }
|
| | | BlameCommand blameCommand = new BlameCommand(r);
|
| | | BlameCommand blameCommand = new BlameCommand(repository);
|
| | | blameCommand.setFilePath(blobPath);
|
| | | blameCommand.setStartCommit(r.resolve(objectId));
|
| | | blameCommand.setStartCommit(repository.resolve(objectId));
|
| | | BlameResult blameResult = blameCommand.call();
|
| | | RawText rawText = blameResult.getResultContents();
|
| | | int length = rawText.size();
|
| | |
| | | *
|
| | | * @param file
|
| | | * @param lineEnding
|
| | | * @return
|
| | | * @return the string content of the file
|
| | | */
|
| | | public static String readContent(File file, String lineEnding) {
|
| | | StringBuilder sb = new StringBuilder();
|
| | |
| | |
|
| | | import org.eclipse.jgit.diff.RawText;
|
| | |
|
| | | /**
|
| | | * Generates an html snippet of a diff in Gitblit's style.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class GitBlitDiffFormatter extends GitWebDiffFormatter {
|
| | |
|
| | | private final OutputStream os;
|
| | |
| | | import org.eclipse.jgit.diff.DiffFormatter;
|
| | | import org.eclipse.jgit.diff.RawText;
|
| | |
|
| | | /**
|
| | | * Returns an html snippet of the diff in the standard Gitweb style.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class GitWebDiffFormatter extends DiffFormatter {
|
| | |
|
| | | private final OutputStream os;
|
| | |
| | | import org.tautua.markdownpapers.Markdown;
|
| | | import org.tautua.markdownpapers.parser.ParseException;
|
| | |
|
| | | /**
|
| | | * Utility methods for transforming raw markdown text to html.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class MarkdownUtils {
|
| | |
|
| | | /**
|
| | | * Returns the html version of the markdown source text.
|
| | | * |
| | | * @param markdown
|
| | | * @return html version of markdown text
|
| | | * @throws java.text.ParseException
|
| | | */
|
| | | public static String transformMarkdown(String markdown) throws java.text.ParseException {
|
| | | try {
|
| | | return transformMarkdown(new StringReader(markdown));
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the html version of the markdown source reader. The reader is
|
| | | * closed regardless of success or failure.
|
| | | * |
| | | * @param markdownReader
|
| | | * @return html version of the markdown text
|
| | | * @throws java.text.ParseException
|
| | | */
|
| | | public static String transformMarkdown(Reader markdownReader) throws java.text.ParseException {
|
| | | // Read raw markdown content and transform it to html
|
| | | StringWriter writer = new StringWriter();
|
| | |
| | | import com.gitblit.models.Metric;
|
| | | import com.gitblit.models.RefModel;
|
| | |
|
| | | /**
|
| | | * Utility class for collecting metrics on a branch, tag, or other ref within
|
| | | * the repository.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class MetricUtils {
|
| | |
|
| | | private static final Logger LOGGER = LoggerFactory.getLogger(MetricUtils.class);
|
| | |
|
| | | public static List<Metric> getDateMetrics(Repository r, String objectId, boolean includeTotal,
|
| | | String format) {
|
| | | /**
|
| | | * Returns the list of metrics for the specified commit reference, branch,
|
| | | * or tag within the repository. If includeTotal is true, the total of all
|
| | | * the metrics will be included as the first element in the returned list.
|
| | | * |
| | | * If the dateformat is unspecified an attempt is made to determine an
|
| | | * appropriate date format by determining the time difference between the
|
| | | * first commit on the branch and the most recent commit. This assumes that
|
| | | * the commits are linear.
|
| | | * |
| | | * @param repository
|
| | | * @param objectId
|
| | | * if null or empty, HEAD is assumed.
|
| | | * @param includeTotal
|
| | | * @param dateFormat
|
| | | * @return list of metrics
|
| | | */
|
| | | public static List<Metric> getDateMetrics(Repository repository, String objectId,
|
| | | boolean includeTotal, String dateFormat) {
|
| | | Metric total = new Metric("TOTAL");
|
| | | final Map<String, Metric> metricMap = new HashMap<String, Metric>();
|
| | | if (StringUtils.isEmpty(objectId)) {
|
| | | objectId = Constants.HEAD;
|
| | | }
|
| | | if (JGitUtils.hasCommits(r)) {
|
| | | final List<RefModel> tags = JGitUtils.getTags(r, true, -1);
|
| | | if (JGitUtils.hasCommits(repository)) {
|
| | | final List<RefModel> tags = JGitUtils.getTags(repository, true, -1);
|
| | | final Map<ObjectId, RefModel> tagMap = new HashMap<ObjectId, RefModel>();
|
| | | for (RefModel tag : tags) {
|
| | | tagMap.put(tag.getReferencedObjectId(), tag);
|
| | | }
|
| | | RevWalk revWalk = null;
|
| | | try {
|
| | | RevWalk walk = new RevWalk(r);
|
| | | ObjectId object = r.resolve(objectId);
|
| | | RevCommit lastCommit = walk.parseCommit(object);
|
| | | walk.markStart(lastCommit);
|
| | | revWalk = new RevWalk(repository);
|
| | | ObjectId object = repository.resolve(objectId);
|
| | | RevCommit lastCommit = revWalk.parseCommit(object);
|
| | | revWalk.markStart(lastCommit);
|
| | |
|
| | | DateFormat df;
|
| | | if (StringUtils.isEmpty(format)) {
|
| | | if (StringUtils.isEmpty(dateFormat)) {
|
| | | // dynamically determine date format
|
| | | RevCommit firstCommit = JGitUtils.getFirstCommit(r, Constants.HEAD);
|
| | | RevCommit firstCommit = JGitUtils.getFirstCommit(repository, Constants.HEAD);
|
| | | int diffDays = (lastCommit.getCommitTime() - firstCommit.getCommitTime())
|
| | | / (60 * 60 * 24);
|
| | | total.duration = diffDays;
|
| | |
| | | }
|
| | | } else {
|
| | | // use specified date format
|
| | | df = new SimpleDateFormat(format);
|
| | | df = new SimpleDateFormat(dateFormat);
|
| | | }
|
| | |
|
| | | Iterable<RevCommit> revlog = walk;
|
| | | Iterable<RevCommit> revlog = revWalk;
|
| | | for (RevCommit rev : revlog) {
|
| | | Date d = JGitUtils.getCommitDate(rev);
|
| | | String p = df.format(d);
|
| | |
| | | }
|
| | | } catch (Throwable t) {
|
| | | LOGGER.error("Failed to mine log history for date metrics", t);
|
| | | } finally {
|
| | | if (revWalk != null) {
|
| | | revWalk.dispose();
|
| | | }
|
| | | }
|
| | | }
|
| | | List<String> keys = new ArrayList<String>(metricMap.keySet());
|
| | |
| | | return metrics;
|
| | | }
|
| | |
|
| | | public static List<Metric> getAuthorMetrics(Repository r, String objectId, boolean byEmail) {
|
| | | /**
|
| | | * Returns a list of author metrics for the specified repository.
|
| | | * |
| | | * @param repository
|
| | | * @param objectId
|
| | | * if null or empty, HEAD is assumed.
|
| | | * @param byEmailAddress
|
| | | * group metrics by author email address otherwise by author name
|
| | | * @return list of metrics
|
| | | */
|
| | | public static List<Metric> getAuthorMetrics(Repository repository, String objectId,
|
| | | boolean byEmailAddress) {
|
| | | final Map<String, Metric> metricMap = new HashMap<String, Metric>();
|
| | | if (StringUtils.isEmpty(objectId)) {
|
| | | objectId = Constants.HEAD;
|
| | | }
|
| | | if (JGitUtils.hasCommits(r)) {
|
| | | if (JGitUtils.hasCommits(repository)) {
|
| | | try {
|
| | | RevWalk walk = new RevWalk(r);
|
| | | ObjectId object = r.resolve(objectId);
|
| | | RevWalk walk = new RevWalk(repository);
|
| | | ObjectId object = repository.resolve(objectId);
|
| | | RevCommit lastCommit = walk.parseCommit(object);
|
| | | walk.markStart(lastCommit);
|
| | |
|
| | | Iterable<RevCommit> revlog = walk;
|
| | | for (RevCommit rev : revlog) {
|
| | | String p;
|
| | | if (byEmail) {
|
| | | if (byEmailAddress) {
|
| | | p = rev.getAuthorIdent().getEmailAddress().toLowerCase();
|
| | | if (StringUtils.isEmpty(p)) {
|
| | | p = rev.getAuthorIdent().getName().toLowerCase();
|
| | |
| | |
|
| | | import com.gitblit.Constants;
|
| | |
|
| | | /**
|
| | | * A diff formatter that outputs standard patch content.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class PatchFormatter extends DiffFormatter {
|
| | |
|
| | | private final OutputStream os;
|
| | |
| | | import java.util.List;
|
| | | import java.util.regex.PatternSyntaxException;
|
| | |
|
| | | /**
|
| | | * Utility class of string functions.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class StringUtils {
|
| | |
|
| | | public static final String MD5_TYPE = "MD5:";
|
| | |
|
| | | /**
|
| | | * Returns true if the string is null or empty.
|
| | | * |
| | | * @param value
|
| | | * @return true if string is null or empty
|
| | | */
|
| | | public static boolean isEmpty(String value) {
|
| | | return value == null || value.trim().length() == 0;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Replaces carriage returns and line feeds with html line breaks.
|
| | | * |
| | | * @param string
|
| | | * @return plain text with html line breaks
|
| | | */
|
| | | public static String breakLinesForHtml(String string) {
|
| | | return string.replace("\r\n", "<br/>").replace("\r", "<br/>").replace("\n", "<br/>");
|
| | | }
|
| | |
|
| | | /**
|
| | | * Prepare text for html presentation. Replace sensitive characters with
|
| | | * html entities.
|
| | | * |
| | | * @param inStr
|
| | | * @param changeSpace
|
| | | * @return plain text escaped for html
|
| | | */
|
| | | public static String escapeForHtml(String inStr, boolean changeSpace) {
|
| | | StringBuffer retStr = new StringBuffer();
|
| | | int i = 0;
|
| | |
| | | return retStr.toString();
|
| | | }
|
| | |
|
| | | /**
|
| | | * Decode html entities back into plain text characters.
|
| | | * |
| | | * @param inStr
|
| | | * @return returns plain text from html
|
| | | */
|
| | | public static String decodeFromHtml(String inStr) {
|
| | | return inStr.replace("&", "&").replace("<", "<").replace(">", ">")
|
| | | .replace(""", "\"").replace(" ", " ");
|
| | | }
|
| | |
|
| | | /**
|
| | | * Encodes a url parameter by escaping troublesome characters.
|
| | | * |
| | | * @param inStr
|
| | | * @return properly escaped url
|
| | | */
|
| | | public static String encodeURL(String inStr) {
|
| | | StringBuffer retStr = new StringBuffer();
|
| | | int i = 0;
|
| | |
| | | return retStr.toString();
|
| | | }
|
| | |
|
| | | /**
|
| | | * Flatten the list of strings into a single string with a space separator.
|
| | | * |
| | | * @param values
|
| | | * @return flattened list
|
| | | */
|
| | | public static String flattenStrings(List<String> values) {
|
| | | return flattenStrings(values, " ");
|
| | | }
|
| | |
|
| | | /**
|
| | | * Flatten the list of strings into a single string with the specified
|
| | | * separator.
|
| | | * |
| | | * @param values
|
| | | * @param separator
|
| | | * @return flattened list
|
| | | */
|
| | | public static String flattenStrings(List<String> values, String separator) {
|
| | | StringBuilder sb = new StringBuilder();
|
| | | for (String value : values) {
|
| | |
| | | return sb.toString().trim();
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns a string trimmed to a maximum length with trailing ellipses. If
|
| | | * the string length is shorter than the max, the original string is
|
| | | * returned.
|
| | | * |
| | | * @param value
|
| | | * @param max
|
| | | * @return trimmed string
|
| | | */
|
| | | public static String trimString(String value, int max) {
|
| | | if (value.length() <= max) {
|
| | | return value;
|
| | |
| | | return value.substring(0, max - 3) + "...";
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns a trimmed shortlog message.
|
| | | * |
| | | * @param string
|
| | | * @return trimmed shortlog message
|
| | | */
|
| | | public static String trimShortLog(String string) {
|
| | | return trimString(string, 60);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Left pad a string with the specified character, if the string length is
|
| | | * less than the specified length.
|
| | | * |
| | | * @param input
|
| | | * @param length
|
| | | * @param pad
|
| | | * @return left-padded string
|
| | | */
|
| | | public static String leftPad(String input, int length, char pad) {
|
| | | if (input.length() < length) {
|
| | | StringBuilder sb = new StringBuilder();
|
| | |
| | | return input;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Right pad a string with the specified character, if the string length is
|
| | | * less then the specified length.
|
| | | * |
| | | * @param input
|
| | | * @param length
|
| | | * @param pad
|
| | | * @return right-padded string
|
| | | */
|
| | | public static String rightPad(String input, int length, char pad) {
|
| | | if (input.length() < length) {
|
| | | StringBuilder sb = new StringBuilder();
|
| | |
| | | return input;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Calculates the SHA1 of the string.
|
| | | * |
| | | * @param text
|
| | | * @return sha1 of the string
|
| | | */
|
| | | public static String getSHA1(String text) {
|
| | | try {
|
| | | byte[] bytes = text.getBytes("iso-8859-1");
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | /**
|
| | | * Calculates the SHA1 of the byte array.
|
| | | * |
| | | * @param bytes
|
| | | * @return sha1 of the byte array
|
| | | */
|
| | | public static String getSHA1(byte[] bytes) {
|
| | | try {
|
| | | MessageDigest md = MessageDigest.getInstance("SHA-1");
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | /**
|
| | | * Calculates the MD5 of the string.
|
| | | * |
| | | * @param string
|
| | | * @return md5 of the string
|
| | | */
|
| | | public static String getMD5(String string) {
|
| | | try {
|
| | | MessageDigest md = MessageDigest.getInstance("MD5");
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the hex representation of the byte array.
|
| | | * |
| | | * @param bytes
|
| | | * @return byte array as hex string
|
| | | */
|
| | | private static String toHex(byte[] bytes) {
|
| | | StringBuilder sb = new StringBuilder(bytes.length * 2);
|
| | | for (int i = 0; i < bytes.length; i++) {
|
| | |
| | | return sb.toString();
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the root path of the specified path. Returns a blank string if
|
| | | * there is no root path.
|
| | | * |
| | | * @param path
|
| | | * @return root path or blank
|
| | | */
|
| | | public static String getRootPath(String path) {
|
| | | if (path.indexOf('/') > -1) {
|
| | | return path.substring(0, path.lastIndexOf('/'));
|
| | |
| | | return "";
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the path remainder after subtracting the basePath from the
|
| | | * fullPath.
|
| | | * |
| | | * @param basePath
|
| | | * @param fullPath
|
| | | * @return the relative path
|
| | | */
|
| | | public static String getRelativePath(String basePath, String fullPath) {
|
| | | String relativePath = fullPath.substring(basePath.length()).replace('\\', '/');
|
| | | if (relativePath.charAt(0) == '/') {
|
| | |
| | | return relativePath;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Splits the space-separated string into a list of strings.
|
| | | * |
| | | * @param value
|
| | | * @return list of strings
|
| | | */
|
| | | public static List<String> getStringsFromValue(String value) {
|
| | | return getStringsFromValue(value, " ");
|
| | | }
|
| | |
|
| | | /**
|
| | | * Splits the string into a list of string by the specified separator.
|
| | | * |
| | | * @param value
|
| | | * @param separator
|
| | | * @return list of strings
|
| | | */
|
| | | public static List<String> getStringsFromValue(String value, String separator) {
|
| | | List<String> strings = new ArrayList<String>();
|
| | | try {
|
| | |
| | | import com.sun.syndication.io.FeedException;
|
| | | import com.sun.syndication.io.SyndFeedOutput;
|
| | |
|
| | | /**
|
| | | * Utility class for RSS feeds.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class SyndicationUtils {
|
| | |
|
| | | /**
|
| | | * Outputs an RSS feed of the list of commits to the outputstream.
|
| | | * |
| | | * @param hostUrl
|
| | | * @param title
|
| | | * @param description
|
| | | * @param repository
|
| | | * @param commits
|
| | | * @param os
|
| | | * @throws IOException
|
| | | * @throws FeedException
|
| | | */
|
| | | public static void toRSS(String hostUrl, String title, String description, String repository,
|
| | | List<RevCommit> commits, OutputStream os) throws IOException, FeedException {
|
| | |
|
| | |
| | | import com.gitblit.models.TicketModel;
|
| | | import com.gitblit.models.TicketModel.Comment;
|
| | |
|
| | | /**
|
| | | * Utility class for reading Ticgit issues.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class TicgitUtils {
|
| | |
|
| | | static final Logger LOGGER = LoggerFactory.getLogger(TicgitUtils.class);
|
| | |
|
| | | public static RefModel getTicketsBranch(Repository r) {
|
| | | /**
|
| | | * Returns a RefModel for the Ticgit branch in the repository. If the branch
|
| | | * can not be found, null is returned.
|
| | | * |
| | | * @param repository
|
| | | * @return a refmodel for the ticgit branch or null
|
| | | */
|
| | | public static RefModel getTicketsBranch(Repository repository) {
|
| | | RefModel ticgitBranch = null;
|
| | | try {
|
| | | // search for ticgit branch in local heads
|
| | | for (RefModel ref : JGitUtils.getLocalBranches(r, false, -1)) {
|
| | | for (RefModel ref : JGitUtils.getLocalBranches(repository, false, -1)) {
|
| | | if (ref.displayName.endsWith("ticgit")) {
|
| | | ticgitBranch = ref;
|
| | | break;
|
| | |
| | |
|
| | | // search for ticgit branch in remote heads
|
| | | if (ticgitBranch == null) {
|
| | | for (RefModel ref : JGitUtils.getRemoteBranches(r, false, -1)) {
|
| | | for (RefModel ref : JGitUtils.getRemoteBranches(repository, false, -1)) {
|
| | | if (ref.displayName.endsWith("ticgit")) {
|
| | | ticgitBranch = ref;
|
| | | break;
|
| | |
| | | return ticgitBranch;
|
| | | }
|
| | |
|
| | | public static List<TicketModel> getTickets(Repository r) {
|
| | | RefModel ticgitBranch = getTicketsBranch(r);
|
| | | /**
|
| | | * Returns a list of all tickets in the ticgit branch of the repository.
|
| | | * |
| | | * @param repository
|
| | | * @return list of tickets
|
| | | */
|
| | | public static List<TicketModel> getTickets(Repository repository) {
|
| | | RefModel ticgitBranch = getTicketsBranch(repository);
|
| | | if (ticgitBranch == null) {
|
| | | return null;
|
| | | }
|
| | | RevCommit commit = (RevCommit) ticgitBranch.referencedObject;
|
| | | List<PathModel> paths = JGitUtils.getFilesInPath(r, null, commit);
|
| | | List<PathModel> paths = JGitUtils.getFilesInPath(repository, null, commit);
|
| | | List<TicketModel> tickets = new ArrayList<TicketModel>();
|
| | | for (PathModel ticketFolder : paths) {
|
| | | if (ticketFolder.isTree()) {
|
| | | try {
|
| | | TicketModel t = new TicketModel(ticketFolder.name);
|
| | | readTicketContents(r, ticgitBranch, t);
|
| | | loadTicketContents(repository, ticgitBranch, t);
|
| | | tickets.add(t);
|
| | | } catch (Throwable t) {
|
| | | LOGGER.error("Failed to get a ticket!", t);
|
| | |
| | | return tickets;
|
| | | }
|
| | |
|
| | | public static TicketModel getTicket(Repository r, String ticketFolder) {
|
| | | RefModel ticketsBranch = getTicketsBranch(r);
|
| | | /**
|
| | | * Returns a TicketModel for the specified ticgit ticket. Returns null if
|
| | | * the ticket does not exist or some other error occurs.
|
| | | * |
| | | * @param repository
|
| | | * @param ticketFolder
|
| | | * @return a ticket
|
| | | */
|
| | | public static TicketModel getTicket(Repository repository, String ticketFolder) {
|
| | | RefModel ticketsBranch = getTicketsBranch(repository);
|
| | | if (ticketsBranch != null) {
|
| | | try {
|
| | | TicketModel ticket = new TicketModel(ticketFolder);
|
| | | readTicketContents(r, ticketsBranch, ticket);
|
| | | loadTicketContents(repository, ticketsBranch, ticket);
|
| | | return ticket;
|
| | | } catch (Throwable t) {
|
| | | LOGGER.error("Failed to get ticket " + ticketFolder, t);
|
| | |
| | | return null;
|
| | | }
|
| | |
|
| | | private static void readTicketContents(Repository r, RefModel ticketsBranch, TicketModel ticket) {
|
| | | /**
|
| | | * Loads the contents of the ticket.
|
| | | * |
| | | * @param repository
|
| | | * @param ticketsBranch
|
| | | * @param ticket
|
| | | */
|
| | | private static void loadTicketContents(Repository repository, RefModel ticketsBranch,
|
| | | TicketModel ticket) {
|
| | | RevCommit commit = (RevCommit) ticketsBranch.referencedObject;
|
| | | List<PathModel> ticketFiles = JGitUtils.getFilesInPath(r, ticket.name, commit);
|
| | | List<PathModel> ticketFiles = JGitUtils.getFilesInPath(repository, ticket.name, commit);
|
| | | for (PathModel file : ticketFiles) {
|
| | | String content = JGitUtils.getStringContent(r, commit.getTree(), file.path).trim();
|
| | | String content = JGitUtils.getStringContent(repository, commit.getTree(), file.path)
|
| | | .trim();
|
| | | if (file.name.equals("TICKET_ID")) {
|
| | | ticket.id = content;
|
| | | } else if (file.name.equals("TITLE")) {
|
| | |
| | | import java.util.Calendar;
|
| | | import java.util.Date;
|
| | |
|
| | | /**
|
| | | * Utility class of time functions.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class TimeUtils {
|
| | | public static final long MIN = 1000 * 60L;
|
| | |
|
| | |
| | |
|
| | | public static final long ONEYEAR = ONEDAY * 365L;
|
| | |
|
| | | /**
|
| | | * Returns true if date is today.
|
| | | * |
| | | * @param date
|
| | | * @return true if date is today
|
| | | */
|
| | | public static boolean isToday(Date date) {
|
| | | return (System.currentTimeMillis() - date.getTime()) < ONEDAY;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns true if date is yesterday.
|
| | | * |
| | | * @param date
|
| | | * @return true if date is yesterday
|
| | | */
|
| | | public static boolean isYesterday(Date date) {
|
| | | Calendar cal = Calendar.getInstance();
|
| | | cal.setTime(date);
|
| | |
| | | return (System.currentTimeMillis() - cal.getTimeInMillis()) < ONEDAY;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the string representation of the duration as days, months and/or
|
| | | * years.
|
| | | * |
| | | * @param days
|
| | | * @return duration as string in days, months, and/or years
|
| | | */
|
| | | public static String duration(int days) {
|
| | | if (days <= 60) {
|
| | | return days + (days > 1 ? " days" : " day");
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the number of minutes ago between the start time and the end
|
| | | * time.
|
| | | * |
| | | * @param date
|
| | | * @param endTime
|
| | | * @param roundup
|
| | | * @return difference in minutes
|
| | | */
|
| | | public static int minutesAgo(Date date, long endTime, boolean roundup) {
|
| | | long diff = endTime - date.getTime();
|
| | | int mins = (int) (diff / MIN);
|
| | |
| | | return mins;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Return the difference in minutes between now and the date.
|
| | | * |
| | | * @param date
|
| | | * @param roundup
|
| | | * @return minutes ago
|
| | | */
|
| | | public static int minutesAgo(Date date, boolean roundup) {
|
| | | return minutesAgo(date, System.currentTimeMillis(), roundup);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Return the difference in hours between now and the date.
|
| | | * |
| | | * @param date
|
| | | * @param roundup
|
| | | * @return hours ago
|
| | | */
|
| | | public static int hoursAgo(Date date, boolean roundup) {
|
| | | long diff = System.currentTimeMillis() - date.getTime();
|
| | | int hours = (int) (diff / ONEHOUR);
|
| | |
| | | return hours;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Return the difference in days between now and the date.
|
| | | * |
| | | * @param date
|
| | | * @param roundup
|
| | | * @return days ago
|
| | | */
|
| | | public static int daysAgo(Date date, boolean roundup) {
|
| | | long diff = System.currentTimeMillis() - date.getTime();
|
| | | int days = (int) (diff / ONEDAY);
|
| | |
| | | return days;
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the string representation of the duration between now and the
|
| | | * date.
|
| | | * |
| | | * @param date
|
| | | * @return duration as a string
|
| | | */
|
| | | public static String timeAgo(Date date) {
|
| | | return timeAgo(date, false);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the CSS class for the date based on its age from Now.
|
| | | * |
| | | * @param date
|
| | | * @return the css class
|
| | | */
|
| | | public static String timeAgoCss(Date date) {
|
| | | return timeAgo(date, true);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the string representation of the duration OR the css class for
|
| | | * the duration.
|
| | | * |
| | | * @param date
|
| | | * @param css
|
| | | * @return the string representation of the duration OR the css class
|
| | | */
|
| | | private static String timeAgo(Date date, boolean css) {
|
| | | String ago = null;
|
| | | if (isToday(date) || isYesterday(date)) {
|