1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.rat.documentation.options;
20
21 import java.io.File;
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Objects;
27 import java.util.Optional;
28 import java.util.Set;
29 import java.util.TreeMap;
30 import java.util.stream.Collectors;
31
32 import org.apache.commons.cli.Option;
33 import org.apache.commons.lang3.StringUtils;
34 import org.apache.commons.text.WordUtils;
35 import org.apache.rat.OptionCollection;
36 import org.apache.rat.commandline.Arg;
37 import org.apache.rat.document.DocumentName;
38 import org.apache.rat.ui.ArgumentTracker;
39 import org.apache.rat.ui.UIOptionCollection;
40 import org.apache.rat.utils.CasedString;
41
42 import static java.lang.String.format;
43
44
45
46
47
48 public final class AntOptionCollection extends UIOptionCollection<AntOption> {
49
50 private static final Map<String, String> RENAME_MAP;
51
52
53
54
55 private static final String DEFAULT_XML = "<%1$s>%%s</%1$s>%n";
56
57
58 private static final Map<String, Map<String, String>> REQUIRED_ATTRIBUTES = new HashMap<>();
59
60 private static final List<Class<?>> ATTRIBUTE_TYPES = new ArrayList<>();
61
62
63 private final Map<Option, Option> conversionMap;
64
65 static {
66 RENAME_MAP = new HashMap<>();
67 RENAME_MAP.put("addLicense", "add-license");
68
69 Map<String, String> attributes = new HashMap<>();
70 attributes.put("editLicense", "true");
71 REQUIRED_ATTRIBUTES.put("copyright", attributes);
72 REQUIRED_ATTRIBUTES.put("editCopyright", attributes);
73 REQUIRED_ATTRIBUTES.put("force", attributes);
74 REQUIRED_ATTRIBUTES.put("editOverwrite", attributes);
75
76
77 ATTRIBUTE_TYPES.add(String.class);
78 ATTRIBUTE_TYPES.add(String[].class);
79 ATTRIBUTE_TYPES.add(Integer.class);
80 ATTRIBUTE_TYPES.add(Long.class);
81 ATTRIBUTE_TYPES.add(File.class);
82 ATTRIBUTE_TYPES.add(DocumentName.class);
83 }
84
85 public static Map<String, String> getRenameMap() {
86 return new TreeMap<>(RENAME_MAP);
87 }
88
89
90 public static final AntOptionCollection INSTANCE = new Builder().build();
91
92
93
94
95 private AntOptionCollection(final Builder builder) {
96 super(builder);
97 conversionMap = builder.conversions;
98 }
99
100 public Set<AntOption> convertedFrom(final AntOption antOption) {
101 return conversionMap.entrySet().stream().filter(e -> e.getValue().equals(antOption.getOption()))
102 .map(e -> getMappedOption(e.getKey()))
103 .filter(Optional::isPresent)
104 .map(Optional::get)
105 .collect(Collectors.toSet());
106 }
107
108
109
110
111
112
113 public AntOption getActualAntOption(final AntOption antOption) {
114 Option opt = conversionMap.get(antOption.getOption());
115 return opt == null ? antOption : getMappedOption(opt).orElse(antOption);
116 }
117
118 public boolean isAttribute(final AntOption antOption) {
119 Option opt = antOption.getOption();
120 return (!opt.hasArg() || opt.getArgs() == 1) && convertedFrom(antOption).isEmpty() &&
121 ATTRIBUTE_TYPES.contains(opt.getType());
122 }
123
124 public Map<String, String> getRequiredAttributes(final String name) {
125 return REQUIRED_ATTRIBUTES.get(name);
126 }
127
128 BuildType buildType(final OptionCollection.ArgumentType type) {
129 return switch (type) {
130 case FILE, DIRORARCHIVE -> new BuildType("filename") {
131 @Override
132 protected String getMethodFormat(final AntOption antOption) {
133 return " <fileset file='%s' />\n";
134 }
135 };
136 case NONE -> new BuildType("");
137 case COUNTERPATTERN -> new BuildType("cntr");
138 case EXPRESSION -> new BuildType("expr");
139 case STANDARDCOLLECTION -> new BuildType("std");
140 case LICENSEID, FAMILYID -> new BuildType("lst");
141 default -> new BuildType(type.getDisplayName()) {
142 @Override
143 protected String getMethodFormat(final AntOption antOption) {
144 return String.format(DEFAULT_XML, WordUtils.uncapitalize(antOption.getArgName()));
145 }
146 };
147 };
148 }
149
150 public static Builder builder() {
151 return new Builder();
152 }
153
154
155
156
157
158
159 static String rename(final String name) {
160 return StringUtils.defaultIfEmpty(RENAME_MAP.get(name), name);
161 }
162
163
164
165
166
167
168 static CasedString createName(final Option option) {
169 List<String> pluralEndings = List.of("approved", "denied");
170 String name = rename(ArgumentTracker.extractKey(option));
171 CasedString casedName = new CasedString(CasedString.StringCase.KEBAB, name);
172 String[] segments = casedName.getSegments();
173 String lastSegment = segments[segments.length - 1];
174 if (option.hasArgs() && !lastSegment.endsWith("s") && !pluralEndings.contains(lastSegment)) {
175 segments[segments.length - 1] += "s";
176 casedName = new CasedString(CasedString.StringCase.KEBAB, segments);
177 }
178 return casedName.as(CasedString.StringCase.PASCAL);
179 }
180
181
182
183
184 public static final class Builder extends UIOptionCollection.Builder<AntOption, Builder> {
185
186 private final Map<Option, Option> conversions = new HashMap<>();
187
188 private Builder() {
189 super(AntOption::new);
190 Arg.getOptions().getOptions()
191 .stream().filter(o -> Objects.isNull(o.getLongOpt()))
192 .forEach(this::unsupported);
193 unsupported(Arg.LOG_LEVEL)
194 .unsupported(Arg.DIR)
195 .unsupported(Arg.SOURCE)
196 .unsupported(Arg.HELP_LICENSES)
197
198 .convert(Arg.LICENSES_APPROVED_FILE, Arg.LICENSES_APPROVED)
199 .convert(Arg.LICENSES_DENIED_FILE, Arg.LICENSES_DENIED)
200 .convert(Arg.FAMILIES_APPROVED_FILE, Arg.FAMILIES_APPROVED)
201 .convert(Arg.FAMILIES_DENIED_FILE, Arg.FAMILIES_DENIED)
202 .convert(Arg.INCLUDE_FILE, Arg.INCLUDE)
203 .convert(Arg.INCLUDE_STD, Arg.INCLUDE)
204 .convert(Arg.EXCLUDE_FILE, Arg.EXCLUDE)
205 .convert(Arg.EXCLUDE_STD, Arg.EXCLUDE);
206 }
207
208 @Override
209 public AntOptionCollection build() {
210 return new AntOptionCollection(this);
211 }
212
213 public Builder convert(final Arg from, final Arg to) {
214 Option mapTo = to.option();
215 for (Option option : from.group().getOptions()) {
216 if (!option.equals(mapTo) && !option.isDeprecated()) {
217 conversions.put(option, mapTo);
218 }
219 }
220 return self();
221 }
222 }
223
224
225
226
227 public static class BuildType {
228
229
230
231 private final String tag;
232
233
234
235 private final boolean addExt;
236
237
238
239
240
241
242 BuildType(final String tag) {
243 this.tag = tag;
244 this.addExt = StringUtils.isNotEmpty(tag);
245 }
246
247
248
249
250
251
252
253 protected String getMethodFormat(final AntOption antOption) {
254 return String.format(DEFAULT_XML, tag);
255 }
256
257
258
259
260
261
262
263
264
265 public String getXml(final AntOption delegateOption, final AntOption antOption, final String data) {
266 String fmt = getMethodFormat(antOption);
267 String value = data == null ? WordUtils.uncapitalize(antOption.getArgName()) : data;
268 String inner = format(fmt, value);
269 return format("<%1$s>%2$s</%1$s>%n", delegateOption.getName(), inner);
270 }
271
272 public String getXml(final AntOption antOption, final String data) {
273 AntOption delegateOption = antOption.getActualAntOption();
274 if (delegateOption.isAttribute()) {
275 return "";
276 } else {
277 return format(getMethodFormat(antOption), data);
278 }
279 }
280
281 public String testName(final AntOption antOption) {
282 return addExt ? format("%s_%s", antOption.getName(), antOption.getArgName()) : antOption.getName();
283 }
284 }
285 }