blob: 96e3cf9b7eadf4f0c5545f6a421fdf9af91d11df [file] [log] [blame]
Dave Borowitzba9c1182013-03-13 14:16:43 -07001// Copyright 2013 Google Inc. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.gitiles;
16
17import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
18import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
19
Dave Borowitz54271462013-11-11 11:43:11 -080020import com.google.common.base.Joiner;
21import com.google.common.collect.ImmutableMap;
22import com.google.gson.reflect.TypeToken;
Dave Borowitzba9c1182013-03-13 14:16:43 -070023
24import org.eclipse.jgit.api.Git;
25import org.eclipse.jgit.api.NameRevCommand;
26import org.eclipse.jgit.api.errors.GitAPIException;
27import org.eclipse.jgit.errors.AmbiguousObjectException;
28import org.eclipse.jgit.errors.RevisionSyntaxException;
29import org.eclipse.jgit.http.server.ServletUtils;
Dave Borowitz54271462013-11-11 11:43:11 -080030import org.eclipse.jgit.lib.Config;
Dave Borowitzba9c1182013-03-13 14:16:43 -070031import org.eclipse.jgit.lib.Constants;
32import org.eclipse.jgit.lib.ObjectId;
33import org.eclipse.jgit.lib.Repository;
34
Dave Borowitz54271462013-11-11 11:43:11 -080035import java.io.IOException;
36import java.io.PrintWriter;
37import java.util.List;
38import java.util.Map;
39
40import javax.servlet.http.HttpServletRequest;
41import javax.servlet.http.HttpServletResponse;
Dave Borowitzba9c1182013-03-13 14:16:43 -070042
43/** Serves an API result describing an object. */
44public class DescribeServlet extends BaseServlet {
45 private static final long serialVersionUID = 1L;
46
47 private static final String ALL_PARAM = "all";
48 private static final String CONTAINS_PARAM = "contains";
49 private static final String TAGS_PARAM = "tags";
50
51 private static boolean getBooleanParam(GitilesView view, String name) {
52 List<String> values = view.getParameters().get(name);
53 return !values.isEmpty()
54 && (values.get(0).equals("") || values.get(0).equals("1"));
55 }
56
Dave Borowitz54271462013-11-11 11:43:11 -080057 protected DescribeServlet(Config cfg) {
58 super(cfg, null);
Dave Borowitzba9c1182013-03-13 14:16:43 -070059 }
60
61 @Override
62 protected void doGetText(HttpServletRequest req, HttpServletResponse res)
63 throws IOException {
64 String name = describe(ServletUtils.getRepository(req), ViewFilter.getView(req), req, res);
65 if (name == null) {
66 return;
67 }
68 PrintWriter out = startRenderText(req, res);
69 out.write(RefServlet.sanitizeRefForText(name));
70 out.close();
71 }
72
73 @Override
74 protected void doGetJson(HttpServletRequest req, HttpServletResponse res)
75 throws IOException {
76 String name = describe(ServletUtils.getRepository(req), ViewFilter.getView(req), req, res);
77 if (name == null) {
78 return;
79 }
80 renderJson(req, res,
81 ImmutableMap.of(ViewFilter.getView(req).getPathPart(), name),
82 new TypeToken<Map<String, String>>() {}.getType());
83 }
84
85 private ObjectId resolve(Repository repo, GitilesView view, HttpServletRequest req,
86 HttpServletResponse res) throws IOException {
87 String rev = view.getPathPart();
88 try {
89 return repo.resolve(rev);
90 } catch (RevisionSyntaxException e) {
91 renderTextError(req, res, SC_BAD_REQUEST,
92 "Invalid revision syntax: " + RefServlet.sanitizeRefForText(rev));
93 return null;
94 } catch (AmbiguousObjectException e) {
95 renderTextError(req, res, SC_BAD_REQUEST, String.format(
96 "Ambiguous short SHA-1 %s (%s)",
97 e.getAbbreviatedObjectId(), Joiner.on(", ").join(e.getCandidates())));
98 return null;
99 }
100 }
101
102 private String describe(Repository repo, GitilesView view, HttpServletRequest req,
103 HttpServletResponse res) throws IOException {
104 if (!getBooleanParam(view, CONTAINS_PARAM)) {
105 res.setStatus(SC_BAD_REQUEST);
106 return null;
107 }
108 ObjectId id = resolve(repo, view, req, res);
109 if (id == null) {
110 return null;
111 }
112 NameRevCommand cmd = nameRevCommand(id, req, res);
113 if (cmd == null) {
114 return null;
115 }
116 String name;
117 try {
118 name = cmd.call().get(id);
119 } catch (GitAPIException e) {
120 throw new IOException(e);
121 }
122 if (name == null) {
123 res.setStatus(SC_NOT_FOUND);
124 return null;
125 }
126 return name;
127 }
128
129 private NameRevCommand nameRevCommand(ObjectId id, HttpServletRequest req,
130 HttpServletResponse res) throws IOException {
131 Repository repo = ServletUtils.getRepository(req);
132 GitilesView view = ViewFilter.getView(req);
133 NameRevCommand cmd = new Git(repo).nameRev();
134 boolean all = getBooleanParam(view, ALL_PARAM);
135 boolean tags = getBooleanParam(view, TAGS_PARAM);
136 if (all && tags) {
137 renderTextError(req, res, SC_BAD_REQUEST, "Cannot specify both \"all\" and \"tags\"");
138 return null;
139 }
140 if (all) {
141 cmd.addPrefix(Constants.R_REFS);
142 } else if (tags) {
143 cmd.addPrefix(Constants.R_TAGS);
144 } else {
145 cmd.addAnnotatedTags();
146 }
147 cmd.add(id);
148 return cmd;
149 }
150}