123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- /*
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
- * Copyright 2013 gitblit.com.
- * and other copyright owners as documented in the project's IP log.
- *
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Distribution License v1.0 which
- * accompanies this distribution, is reproduced below, and is
- * available at http://www.eclipse.org/org/documents/edl-v10.php
- *
- * All rights reserved.
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.gitblit;
-
- import java.awt.BasicStroke;
- import java.awt.Color;
- import java.awt.Graphics;
- import java.awt.Graphics2D;
- import java.awt.RenderingHints;
- import java.awt.Stroke;
- import java.awt.image.BufferedImage;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.io.Serializable;
- import java.util.ArrayList;
- import java.util.LinkedList;
- import java.util.List;
-
- import javax.imageio.ImageIO;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
- import org.eclipse.jgit.lib.Ref;
- import org.eclipse.jgit.lib.Repository;
- import org.eclipse.jgit.revplot.AbstractPlotRenderer;
- import org.eclipse.jgit.revplot.PlotCommit;
- import org.eclipse.jgit.revplot.PlotCommitList;
- import org.eclipse.jgit.revplot.PlotLane;
- import org.eclipse.jgit.revplot.PlotWalk;
- import org.eclipse.jgit.revwalk.RevCommit;
-
- import com.gitblit.utils.JGitUtils;
- import com.gitblit.utils.StringUtils;
-
- /**
- * Handles requests for branch graphs
- *
- * @author James Moger
- *
- */
- public class BranchGraphServlet extends HttpServlet {
-
- private static final long serialVersionUID = 1L;
-
- private static final int LANE_WIDTH = 14;
-
- // must match tr.commit css height
- private static final int ROW_HEIGHT = 24;
-
- private static final int RIGHT_PAD = 2;
-
- private final Stroke[] strokeCache;
-
- public BranchGraphServlet() {
- super();
-
- strokeCache = new Stroke[4];
- for (int i = 1; i < strokeCache.length; i++)
- strokeCache[i] = new BasicStroke(i);
- }
-
- /**
- * Returns an url to this servlet for the specified parameters.
- *
- * @param baseURL
- * @param repository
- * @param objectId
- * @param numberCommits
- * @return an url
- */
- public static String asLink(String baseURL, String repository, String objectId, int numberCommits) {
- if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') {
- baseURL = baseURL.substring(0, baseURL.length() - 1);
- }
- return baseURL + Constants.BRANCH_GRAPH_PATH + "?r=" + repository
- + (objectId == null ? "" : ("&h=" + objectId))
- + (numberCommits > 0 ? ("&l=" + numberCommits) : "");
- }
-
- @Override
- protected long getLastModified(HttpServletRequest req) {
- String repository = req.getParameter("r");
- String objectId = req.getParameter("h");
- Repository r = null;
- try {
- r = GitBlit.self().getRepository(repository);
- if (StringUtils.isEmpty(objectId)) {
- objectId = JGitUtils.getHEADRef(r);
- }
- RevCommit commit = JGitUtils.getCommit(r, objectId);
- return JGitUtils.getCommitDate(commit).getTime();
- } finally {
- if (r != null) {
- r.close();
- }
- }
- }
-
- @Override
- protected void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- InputStream is = null;
- Repository r = null;
- PlotWalk rw = null;
- try {
- String repository = request.getParameter("r");
- String objectId = request.getParameter("h");
- String length = request.getParameter("l");
-
- r = GitBlit.self().getRepository(repository);
-
- rw = new PlotWalk(r);
- if (StringUtils.isEmpty(objectId)) {
- objectId = JGitUtils.getHEADRef(r);
- }
-
- rw.markStart(rw.lookupCommit(r.resolve(objectId)));
-
- // default to the items-per-page setting, unless specified
- int maxCommits = GitBlit.getInteger(Keys.web.itemsPerPage, 50);
- if (!StringUtils.isEmpty(length)) {
- int l = Integer.parseInt(length);
- if (l > 0) {
- maxCommits = l;
- }
- }
-
- // fetch the requested commits plus some extra so that the last
- // commit displayed *likely* has correct lane assignments
- CommitList commitList = new CommitList();
- commitList.source(rw);
- commitList.fillTo(2*maxCommits);
-
- // determine the appropriate width for the image
- int numLanes = 0;
- int numCommits = Math.min(maxCommits, commitList.size());
- for (int i = 0; i < numCommits; i++) {
- PlotCommit<Lane> commit = commitList.get(i);
- int pos = commit.getLane().getPosition();
- numLanes = Math.max(numLanes, pos + 1);
- }
-
- int graphWidth = numLanes * LANE_WIDTH + RIGHT_PAD;
- int rowHeight = ROW_HEIGHT;
-
- // create an image buffer and render the lanes
- BufferedImage image = new BufferedImage(graphWidth, rowHeight*numCommits, BufferedImage.TYPE_INT_ARGB);
- Graphics2D g = null;
- try {
- g = image.createGraphics();
- g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- LanesRenderer renderer = new LanesRenderer();
- for (int i = 0; i < numCommits; i++) {
- PlotCommit<Lane> commit = commitList.get(i);
- Graphics row = g.create(0, i*rowHeight, graphWidth, rowHeight);
- try {
- renderer.paint(row, commit, rowHeight, graphWidth);
- } finally {
- row.dispose();
- row = null;
- }
- }
- } finally {
- if (g != null) {
- g.dispose();
- g = null;
- }
- }
-
- // write the image buffer to the client
- response.setContentType("image/png");
- if (numCommits > 0) {
- response.setHeader("Cache-Control", "public, max-age=60, must-revalidate");
- response.setDateHeader("Last-Modified", JGitUtils.getCommitDate(commitList.get(0)).getTime());
- }
- OutputStream os = response.getOutputStream();
- ImageIO.write(image, "png", os);
- os.flush();
- image.flush();
- image = null;
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (is != null) {
- is.close();
- is = null;
- }
- if (rw != null) {
- rw.dispose();
- rw = null;
- }
- if (r != null) {
- r.close();
- r = null;
- }
- }
- }
-
- private Stroke stroke(final int width) {
- if (width < strokeCache.length)
- return strokeCache[width];
- return new BasicStroke(width);
- }
-
- static class CommitList extends PlotCommitList<Lane> {
- final List<Color> laneColors;
- final LinkedList<Color> colors;
-
- CommitList() {
- laneColors = new ArrayList<Color>();
- laneColors.add(new Color(133, 166, 214));
- laneColors.add(new Color(221, 205, 93));
- laneColors.add(new Color(199, 134, 57));
- laneColors.add(new Color(131, 150, 98));
- laneColors.add(new Color(197, 123, 127));
- laneColors.add(new Color(139, 136, 140));
- laneColors.add(new Color(48, 135, 144));
- laneColors.add(new Color(190, 93, 66));
- laneColors.add(new Color(143, 163, 54));
- laneColors.add(new Color(180, 148, 74));
- laneColors.add(new Color(101, 101, 217));
- laneColors.add(new Color(72, 153, 119));
- laneColors.add(new Color(23, 101, 160));
- laneColors.add(new Color(132, 164, 118));
- laneColors.add(new Color(255, 230, 59));
- laneColors.add(new Color(136, 176, 70));
- laneColors.add(new Color(255, 138, 1));
- laneColors.add(new Color(123, 187, 95));
- laneColors.add(new Color(233, 88, 98));
- laneColors.add(new Color(93, 158, 254));
- laneColors.add(new Color(175, 215, 0));
- laneColors.add(new Color(140, 134, 142));
- laneColors.add(new Color(232, 168, 21));
- laneColors.add(new Color(0, 172, 191));
- laneColors.add(new Color(251, 58, 4));
- laneColors.add(new Color(63, 64, 255));
- laneColors.add(new Color(27, 194, 130));
- laneColors.add(new Color(0, 104, 183));
-
- colors = new LinkedList<Color>();
- repackColors();
- }
-
- private void repackColors() {
- colors.addAll(laneColors);
- }
-
- @Override
- protected Lane createLane() {
- final Lane lane = new Lane();
- if (colors.isEmpty())
- repackColors();
- lane.color = colors.removeFirst();
- return lane;
- }
-
- @Override
- protected void recycleLane(final Lane lane) {
- colors.add(lane.color);
- }
- }
-
- static class Lane extends PlotLane {
-
- private static final long serialVersionUID = 1L;
-
- Color color;
-
- @Override
- public boolean equals(Object o) {
- return super.equals(o) && color.equals(((Lane)o).color);
- }
-
- @Override
- public int hashCode() {
- return super.hashCode() ^ color.hashCode();
- }
- }
-
- class LanesRenderer extends AbstractPlotRenderer<Lane, Color> implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- final Color commitDotFill = new Color(220, 220, 220);
-
- final Color commitDotOutline = new Color(110, 110, 110);
-
- transient Graphics2D g;
-
- void paint(Graphics in, PlotCommit<Lane> commit, int h, int w) {
- g = (Graphics2D) in.create();
- try {
- if (commit != null)
- paintCommit(commit, h);
- } finally {
- g.dispose();
- g = null;
- }
- }
-
- @Override
- protected void drawLine(Color color, int x1, int y1, int x2, int y2, int width) {
- if (y1 == y2) {
- x1 -= width / 2;
- x2 -= width / 2;
- } else if (x1 == x2) {
- y1 -= width / 2;
- y2 -= width / 2;
- }
-
- g.setColor(color);
- g.setStroke(stroke(width));
- g.drawLine(x1, y1, x2, y2);
- }
-
- @Override
- protected void drawCommitDot(int x, int y, int w, int h) {
- g.setColor(commitDotFill);
- g.setStroke(strokeCache[2]);
- g.fillOval(x + 2, y + 1, w - 2, h - 2);
- g.setColor(commitDotOutline);
- g.drawOval(x + 2, y + 1, w - 2, h - 2);
- }
-
- @Override
- protected void drawBoundaryDot(int x, int y, int w, int h) {
- drawCommitDot(x, y, w, h);
- }
-
- @Override
- protected void drawText(String msg, int x, int y) {
- }
-
- @Override
- protected Color laneColor(Lane myLane) {
- return myLane != null ? myLane.color : Color.black;
- }
-
- @Override
- protected int drawLabel(int x, int y, Ref ref) {
- return 0;
- }
- }
- }
|