blob: 545f3aa3261b0327305c0e48ff5964b46ddd74d8 [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
Dave Borowitz54271462013-11-11 11:43:11 -080017import com.google.common.base.Joiner;
18import com.google.common.collect.ImmutableMap;
Masaya Suzuki5cecb862019-03-25 17:35:44 -070019import com.google.gitiles.GitilesRequestFailureException.FailureReason;
Dave Borowitz54271462013-11-11 11:43:11 -080020import com.google.gson.reflect.TypeToken;
Dave Borowitz3b744b12016-08-19 16:11:10 -040021import java.io.IOException;
22import java.io.Writer;
23import java.util.List;
24import java.util.Map;
25import javax.servlet.http.HttpServletRequest;
26import javax.servlet.http.HttpServletResponse;
Dave Borowitzba9c1182013-03-13 14:16:43 -070027import org.eclipse.jgit.api.Git;
28import org.eclipse.jgit.api.NameRevCommand;
29import org.eclipse.jgit.api.errors.GitAPIException;
30import org.eclipse.jgit.errors.AmbiguousObjectException;
31import org.eclipse.jgit.errors.RevisionSyntaxException;
32import org.eclipse.jgit.http.server.ServletUtils;
33import org.eclipse.jgit.lib.Constants;
34import org.eclipse.jgit.lib.ObjectId;
35import org.eclipse.jgit.lib.Repository;
36
Dave Borowitzba9c1182013-03-13 14:16:43 -070037/** Serves an API result describing an object. */
38public class DescribeServlet extends BaseServlet {
39 private static final long serialVersionUID = 1L;
40
41 private static final String ALL_PARAM = "all";
42 private static final String CONTAINS_PARAM = "contains";
43 private static final String TAGS_PARAM = "tags";
44
45 private static boolean getBooleanParam(GitilesView view, String name) {
46 List<String> values = view.getParameters().get(name);
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020047 return !values.isEmpty() && (values.get(0).isEmpty() || values.get(0).equals("1"));
Dave Borowitzba9c1182013-03-13 14:16:43 -070048 }
49
Dave Borowitz8d6d6872014-03-16 15:18:14 -070050 protected DescribeServlet(GitilesAccess.Factory accessFactory) {
51 super(null, accessFactory);
Dave Borowitzba9c1182013-03-13 14:16:43 -070052 }
53
54 @Override
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020055 protected void doGetText(HttpServletRequest req, HttpServletResponse res) throws IOException {
David Pursehouse3484ab82019-05-13 06:55:07 +020056 String name = describe(ServletUtils.getRepository(req), ViewFilter.getView(req), req);
Dave Borowitzba9c1182013-03-13 14:16:43 -070057 if (name == null) {
58 return;
59 }
David Pursehousec3e772a2016-06-15 21:49:35 +090060 try (Writer out = startRenderText(req, res)) {
61 out.write(RefServlet.sanitizeRefForText(name));
62 }
Dave Borowitzba9c1182013-03-13 14:16:43 -070063 }
64
65 @Override
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020066 protected void doGetJson(HttpServletRequest req, HttpServletResponse res) throws IOException {
David Pursehouse3484ab82019-05-13 06:55:07 +020067 String name = describe(ServletUtils.getRepository(req), ViewFilter.getView(req), req);
Dave Borowitzba9c1182013-03-13 14:16:43 -070068 if (name == null) {
69 return;
70 }
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020071 renderJson(
72 req,
73 res,
Dave Borowitzba9c1182013-03-13 14:16:43 -070074 ImmutableMap.of(ViewFilter.getView(req).getPathPart(), name),
75 new TypeToken<Map<String, String>>() {}.getType());
76 }
77
David Pursehouse3484ab82019-05-13 06:55:07 +020078 private ObjectId resolve(Repository repo, GitilesView view) throws IOException {
Dave Borowitzba9c1182013-03-13 14:16:43 -070079 String rev = view.getPathPart();
80 try {
81 return repo.resolve(rev);
82 } catch (RevisionSyntaxException e) {
David Ostrovsky1ae7c382020-01-24 08:17:24 +010083 throw new GitilesRequestFailureException(FailureReason.INCORECT_PARAMETER, e)
Masaya Suzuki5cecb862019-03-25 17:35:44 -070084 .withPublicErrorMessage(
85 "Invalid revision syntax: %s", RefServlet.sanitizeRefForText(rev));
Dave Borowitzba9c1182013-03-13 14:16:43 -070086 } catch (AmbiguousObjectException e) {
Masaya Suzuki5cecb862019-03-25 17:35:44 -070087 throw new GitilesRequestFailureException(FailureReason.AMBIGUOUS_OBJECT)
88 .withPublicErrorMessage(
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020089 "Ambiguous short SHA-1 %s (%s)",
Masaya Suzuki5cecb862019-03-25 17:35:44 -070090 e.getAbbreviatedObjectId(), Joiner.on(", ").join(e.getCandidates()));
Dave Borowitzba9c1182013-03-13 14:16:43 -070091 }
92 }
93
David Pursehouse3484ab82019-05-13 06:55:07 +020094 private String describe(Repository repo, GitilesView view, HttpServletRequest req)
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020095 throws IOException {
Dave Borowitzba9c1182013-03-13 14:16:43 -070096 if (!getBooleanParam(view, CONTAINS_PARAM)) {
Masaya Suzuki5cecb862019-03-25 17:35:44 -070097 throw new GitilesRequestFailureException(FailureReason.INCORECT_PARAMETER);
Dave Borowitzba9c1182013-03-13 14:16:43 -070098 }
David Pursehouse3484ab82019-05-13 06:55:07 +020099 ObjectId id = resolve(repo, view);
Dave Borowitzba9c1182013-03-13 14:16:43 -0700100 if (id == null) {
101 return null;
102 }
Dave Borowitzba9c1182013-03-13 14:16:43 -0700103 String name;
Dave Borowitzc35311d2015-08-10 11:21:51 -0400104 try (Git git = new Git(repo)) {
David Pursehouse3484ab82019-05-13 06:55:07 +0200105 NameRevCommand cmd = nameRevCommand(git, id, req);
Dave Borowitzc35311d2015-08-10 11:21:51 -0400106 if (cmd == null) {
107 return null;
108 }
Dave Borowitzba9c1182013-03-13 14:16:43 -0700109 name = cmd.call().get(id);
110 } catch (GitAPIException e) {
111 throw new IOException(e);
112 }
113 if (name == null) {
Masaya Suzuki5cecb862019-03-25 17:35:44 -0700114 throw new GitilesRequestFailureException(FailureReason.OBJECT_NOT_FOUND);
Dave Borowitzba9c1182013-03-13 14:16:43 -0700115 }
116 return name;
117 }
118
David Pursehouse3484ab82019-05-13 06:55:07 +0200119 private NameRevCommand nameRevCommand(Git git, ObjectId id, HttpServletRequest req)
120 throws IOException {
Dave Borowitzba9c1182013-03-13 14:16:43 -0700121 GitilesView view = ViewFilter.getView(req);
Dave Borowitzc35311d2015-08-10 11:21:51 -0400122 NameRevCommand cmd = git.nameRev();
Dave Borowitzba9c1182013-03-13 14:16:43 -0700123 boolean all = getBooleanParam(view, ALL_PARAM);
124 boolean tags = getBooleanParam(view, TAGS_PARAM);
125 if (all && tags) {
Masaya Suzuki5cecb862019-03-25 17:35:44 -0700126 throw new GitilesRequestFailureException(FailureReason.UNSUPPORTED_REVISION_NAMES)
127 .withPublicErrorMessage("Cannot specify both \"all\" and \"tags\"");
Dave Borowitzba9c1182013-03-13 14:16:43 -0700128 }
129 if (all) {
130 cmd.addPrefix(Constants.R_REFS);
131 } else if (tags) {
132 cmd.addPrefix(Constants.R_TAGS);
133 } else {
134 cmd.addAnnotatedTags();
135 }
136 cmd.add(id);
137 return cmd;
138 }
139}