-
-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathAbstractXmlPlugin.java
More file actions
329 lines (283 loc) · 10.8 KB
/
Copy pathAbstractXmlPlugin.java
File metadata and controls
329 lines (283 loc) · 10.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
/*
* XML Format Maven Plugin (https://github.com/acegi/xml-format-maven-plugin)
*
* Copyright 2011-2026 Acegi Technology Pty Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* 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 au.com.acegi.xmlformat;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Parameter;
import org.codehaus.plexus.util.DirectoryScanner;
import org.dom4j.DocumentException;
/**
* Common infrastructure for the various plugin goals.
*/
@SuppressWarnings("DesignForExtension")
public abstract class AbstractXmlPlugin extends AbstractMojo {
/**
* Quote character to use when writing attributes.
*/
@Parameter(property = "attributeQuoteChar", defaultValue = "\"")
@SuppressWarnings("PMD.ImmutableField")
private char attributeQuoteChar = '"';
/**
* The base directory of the project.
*/
@Parameter(defaultValue = ".", readonly = true, required = true, property = "project.basedir")
private File baseDirectory;
/**
* The encoding format.
*/
@Parameter(property = "encoding", defaultValue = "UTF-8")
@SuppressWarnings("PMD.ImmutableField")
private String encoding = "UTF-8";
/**
* A set of file patterns that allow you to exclude certain files/folders from the formatting. In addition to these
* exclusions, the project build directory (typically <code>target</code>) is always excluded if skipTargetFolder is
* true.
*/
@Parameter(property = "excludes")
private String[] excludes;
/**
* Whether or not to expand empty elements to <tagName></tagName>.
*/
@Parameter(property = "expandEmptyElements", defaultValue = "false")
private boolean expandEmptyElements;
/**
* A set of file patterns that dictate which files should be included in the formatting with each file pattern being
* relative to the base directory.
*/
@Parameter(property = "includes")
private String[] includes;
/**
* Indicates the number of spaces to apply when indenting.
*/
@Parameter(property = "indentSize", defaultValue = "2")
private int indentSize;
/**
* Use tabs instead of spaces for indents. If set to <code>true</code>, <code>indentSize</code> will be ignored.
*/
@Parameter(property = "tabIndent", defaultValue = "false")
private boolean tabIndent;
/**
* Sets the line-ending of files after formatting. Valid values are:
* <ul>
* <li><b>"SYSTEM"</b> - Use line endings of current system</li>
* <li><b>"LF"</b> - Use Unix and Mac style line endings</li>
* <li><b>"CRLF"</b> - Use DOS and Windows style line endings</li>
* <li><b>"CR"</b> - Use early Mac style line endings</li>
* </ul>
* This property is only used if {@link #lineSeparator} has its default value. Do not set any value for
* {@link #lineSeparator}.
*/
@Parameter(property = "lineEnding", defaultValue = "LF")
@SuppressWarnings("PMD.ImmutableField")
private LineEnding lineEnding = LineEnding.LF;
/**
* New line separator.
*
* @deprecated Please do not set this value; use {@link #lineEnding} instead
*/
@Parameter(property = "lineSeparator", defaultValue = "\n")
@SuppressWarnings("PMD.ImmutableField")
@Deprecated
private String lineSeparator = "\n";
/**
* Whether or not to print new line after the XML declaration.
*/
@Parameter(property = "newLineAfterDeclaration", defaultValue = "false")
private boolean newLineAfterDeclaration;
/**
* Controls when to output a line.separator every so many tags in case of no lines and total text trimming.
*/
@Parameter(property = "newLineAfterNTags", defaultValue = "0")
private int newLineAfterNTags;
/**
* The default new line flag, set to do new lines only as in original document.
*/
@Parameter(property = "newlines", defaultValue = "true")
private boolean newlines;
/**
* Whether or not to output the encoding in the XML declaration.
*/
@Parameter(property = "omitEncoding", defaultValue = "false")
private boolean omitEncoding;
/**
* Pad string-element boundaries with whitespace.
*/
@Parameter(property = "padText", defaultValue = "false")
private boolean padText;
/**
* Skip XML formatting.
*/
@Parameter(property = "xml-format.skip", defaultValue = "false")
private boolean skip;
/**
* In addition to the exclusions, the project build directory (typically <code>target</code>) is always excluded if
* true.
*/
@Parameter(property = "skipTargetFolder", defaultValue = "true")
private boolean skipTargetFolder = true;
/**
* Whether or not to suppress the XML declaration.
*/
@Parameter(property = "suppressDeclaration", defaultValue = "false")
private boolean suppressDeclaration;
/**
* The project target directory. This is always excluded from formatting.
*/
@Parameter(defaultValue = "${project.build.directory}", readonly = true, required = true)
private File targetDirectory;
/**
* Should we preserve whitespace or not in text nodes.
*/
@Parameter(property = "trimText", defaultValue = "true")
private boolean trimText;
/**
* Whether or not to use XHTML standard.
*/
@Parameter(property = "xhtml", defaultValue = "false")
private boolean xhtml;
/**
* Whether to keep blank lines. A maximum of one line is preserved between each tag.
*/
@Parameter(property = "keepBlankLines", defaultValue = "false")
private boolean keepBlankLines;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
assert baseDirectory != null;
assert targetDirectory != null;
if (skip) {
getLog().info("[xml-format] Skipped");
return;
}
initializeIncludes();
initializeExcludes();
final XmlOutputFormat fmt = buildFormatter();
boolean success = true;
boolean neededFormatting = false;
for (final String inputName : find()) {
final File input = baseDirectory.toPath().resolve(inputName).toFile();
try {
neededFormatting |= processFile(input, fmt);
} catch (final DocumentException | IOException ex) {
success = false;
getLog().error("[xml-format] Error for " + input, ex);
}
}
if (!success) {
throw new MojoFailureException("[xml-format] Failed)");
}
afterAllProcessed(neededFormatting);
}
/**
* Processes a single file found in the project.
*
* @param input
* the file to process
* @param fmt
* the formatting options
*
* @return true if the file required changes to match the formatting style
*
* @throws DocumentException
* if input XML could not be parsed
* @throws IOException
* if output XML stream could not be written
*/
protected abstract boolean processFile(File input, XmlOutputFormat fmt) throws DocumentException, IOException;
/**
* Invoked after all files in the project have been processed.
*
* @param neededFormatting
* whether any processed file required changes to match the formatting style
*
* @throws MojoExecutionException
* if the build must be failed
*/
protected abstract void afterAllProcessed(boolean neededFormatting) throws MojoExecutionException;
void setBaseDirectory(final File baseDirectory) {
this.baseDirectory = baseDirectory;
}
void setExcludes(final String... excludes) {
this.excludes = excludes == null ? null : Arrays.copyOf(excludes, excludes.length);
}
void setIncludes(final String... includes) {
this.includes = includes == null ? null : Arrays.copyOf(includes, includes.length);
}
void setSkip(final boolean skip) {
this.skip = skip;
}
void setSkipTargetFolder(final boolean skipTargetFolder) {
this.skipTargetFolder = skipTargetFolder;
}
void setTargetDirectory(final File targetDirectory) {
this.targetDirectory = targetDirectory;
}
private XmlOutputFormat buildFormatter() {
final XmlOutputFormat fmt = new XmlOutputFormat();
fmt.setAttributeQuoteCharacter(attributeQuoteChar);
fmt.setEncoding(encoding);
fmt.setExpandEmptyElements(expandEmptyElements);
if (tabIndent) {
fmt.setIndent("\t");
} else {
fmt.setIndentSize(indentSize);
}
fmt.setLineSeparator(determineLineSeparator());
fmt.setNewLineAfterDeclaration(newLineAfterDeclaration);
fmt.setNewLineAfterNTags(newLineAfterNTags);
fmt.setNewlines(newlines);
fmt.setOmitEncoding(omitEncoding);
fmt.setPadText(padText);
fmt.setSuppressDeclaration(suppressDeclaration);
fmt.setTrimText(trimText);
fmt.setXHTML(xhtml);
fmt.setKeepBlankLines(keepBlankLines);
return fmt;
}
private String determineLineSeparator() {
return "\n".equals(lineSeparator) ? lineEnding.getChars() : lineSeparator;
}
private String[] find() {
final DirectoryScanner dirScanner = new DirectoryScanner();
dirScanner.setBasedir(baseDirectory);
dirScanner.setIncludes(includes);
final List<String> exclude = new ArrayList<>(Arrays.asList(excludes));
if (skipTargetFolder && baseDirectory.equals(targetDirectory.getParentFile())) {
exclude.add(targetDirectory.getName() + "/**");
}
final String[] excluded = new String[exclude.size()];
dirScanner.setExcludes(exclude.toArray(excluded));
dirScanner.scan();
return dirScanner.getIncludedFiles();
}
private void initializeExcludes() {
if (excludes == null || excludes.length == 0) {
excludes = new String[0];
}
}
private void initializeIncludes() {
if (includes == null || includes.length == 0) {
includes = new String[] { "**/*.xml" };
}
}
}