Line data Source code
1 : // Copyright (C) 2012 The Android Open Source Project 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 : 15 : package com.google.gerrit.server.plugins; 16 : 17 : import static java.util.Comparator.comparing; 18 : import static java.util.stream.Collectors.toMap; 19 : 20 : import com.google.common.collect.Streams; 21 : import com.google.gerrit.common.data.GlobalCapability; 22 : import com.google.gerrit.extensions.annotations.RequiresCapability; 23 : import com.google.gerrit.extensions.api.plugins.Plugins; 24 : import com.google.gerrit.extensions.common.PluginInfo; 25 : import com.google.gerrit.extensions.restapi.BadRequestException; 26 : import com.google.gerrit.extensions.restapi.Response; 27 : import com.google.gerrit.extensions.restapi.RestReadView; 28 : import com.google.gerrit.extensions.restapi.TopLevelResource; 29 : import com.google.gerrit.extensions.restapi.Url; 30 : import com.google.inject.Inject; 31 : import java.util.Locale; 32 : import java.util.SortedMap; 33 : import java.util.TreeMap; 34 : import java.util.regex.Pattern; 35 : import java.util.stream.Stream; 36 : import org.kohsuke.args4j.Option; 37 : 38 : /** List the installed plugins. */ 39 : @RequiresCapability(GlobalCapability.VIEW_PLUGINS) 40 : public class ListPlugins implements RestReadView<TopLevelResource> { 41 : private final PluginLoader pluginLoader; 42 : 43 : private boolean all; 44 : private int limit; 45 : private int start; 46 : private String matchPrefix; 47 : private String matchSubstring; 48 : private String matchRegex; 49 : 50 : @Option( 51 : name = "--all", 52 : aliases = {"-a"}, 53 : usage = "List all plugins, including disabled plugins") 54 : public void setAll(boolean all) { 55 1 : this.all = all; 56 1 : } 57 : 58 : @Option( 59 : name = "--limit", 60 : aliases = {"-n"}, 61 : metaVar = "CNT", 62 : usage = "maximum number of plugins to list") 63 : public void setLimit(int limit) { 64 1 : this.limit = limit; 65 1 : } 66 : 67 : @Option( 68 : name = "--start", 69 : aliases = {"-S"}, 70 : metaVar = "CNT", 71 : usage = "number of plugins to skip") 72 : public void setStart(int start) { 73 1 : this.start = start; 74 1 : } 75 : 76 : @Option( 77 : name = "--prefix", 78 : aliases = {"-p"}, 79 : metaVar = "PREFIX", 80 : usage = "match plugin prefix") 81 : public void setMatchPrefix(String matchPrefix) { 82 1 : this.matchPrefix = matchPrefix; 83 1 : } 84 : 85 : @Option( 86 : name = "--match", 87 : aliases = {"-m"}, 88 : metaVar = "MATCH", 89 : usage = "match plugin substring") 90 : public void setMatchSubstring(String matchSubstring) { 91 1 : this.matchSubstring = matchSubstring; 92 1 : } 93 : 94 : @Option(name = "-r", metaVar = "REGEX", usage = "match plugin regex") 95 : public void setMatchRegex(String matchRegex) { 96 1 : this.matchRegex = matchRegex; 97 1 : } 98 : 99 : @Inject 100 3 : protected ListPlugins(PluginLoader pluginLoader) { 101 3 : this.pluginLoader = pluginLoader; 102 3 : } 103 : 104 : public ListPlugins request(Plugins.ListRequest request) { 105 1 : this.setAll(request.getAll()); 106 1 : this.setStart(request.getStart()); 107 1 : this.setLimit(request.getLimit()); 108 1 : this.setMatchPrefix(request.getPrefix()); 109 1 : this.setMatchSubstring(request.getSubstring()); 110 1 : this.setMatchRegex(request.getRegex()); 111 1 : return this; 112 : } 113 : 114 : @Override 115 : public Response<SortedMap<String, PluginInfo>> apply(TopLevelResource resource) 116 : throws BadRequestException { 117 2 : Stream<Plugin> s = Streams.stream(pluginLoader.getPlugins(all)); 118 2 : if (matchPrefix != null) { 119 1 : checkMatchOptions(matchSubstring == null && matchRegex == null); 120 1 : s = s.filter(p -> p.getName().startsWith(matchPrefix)); 121 2 : } else if (matchSubstring != null) { 122 1 : checkMatchOptions(matchPrefix == null && matchRegex == null); 123 1 : String substring = matchSubstring.toLowerCase(Locale.US); 124 1 : s = s.filter(p -> p.getName().toLowerCase(Locale.US).contains(substring)); 125 2 : } else if (matchRegex != null) { 126 1 : checkMatchOptions(matchPrefix == null && matchSubstring == null); 127 1 : Pattern pattern = Pattern.compile(matchRegex); 128 1 : s = s.filter(p -> pattern.matcher(p.getName()).matches()); 129 : } 130 2 : s = s.sorted(comparing(Plugin::getName)); 131 2 : if (start > 0) { 132 1 : s = s.skip(start); 133 : } 134 2 : if (limit > 0) { 135 1 : s = s.limit(limit); 136 : } 137 2 : return Response.ok(new TreeMap<>(s.collect(toMap(Plugin::getName, ListPlugins::toPluginInfo)))); 138 : } 139 : 140 : private void checkMatchOptions(boolean cond) throws BadRequestException { 141 1 : if (!cond) { 142 1 : throw new BadRequestException("specify exactly one of p/m/r"); 143 : } 144 1 : } 145 : 146 : public static PluginInfo toPluginInfo(Plugin p) { 147 : String id; 148 : String version; 149 : String apiVersion; 150 : String indexUrl; 151 : String filename; 152 : Boolean disabled; 153 : 154 3 : id = Url.encode(p.getName()); 155 3 : version = p.getVersion(); 156 3 : apiVersion = p.getApiVersion(); 157 3 : disabled = p.isDisabled() ? true : null; 158 3 : if (p.getSrcFile() != null) { 159 3 : indexUrl = String.format("plugins/%s/", p.getName()); 160 3 : filename = p.getSrcFile().getFileName().toString(); 161 : } else { 162 0 : indexUrl = null; 163 0 : filename = null; 164 : } 165 : 166 3 : return new PluginInfo(id, version, apiVersion, indexUrl, filename, disabled); 167 : } 168 : }