Skip to content

Commit

Permalink
#18: add support for xml
Browse files Browse the repository at this point in the history
  • Loading branch information
TheSnoozer committed May 4, 2023
1 parent 8c24df0 commit 1d84b3d
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,8 @@ public enum CommitIdPropertiesOutputFormat {
* Indicator to generate a json file.
*/
JSON,
/**
* Indicator to generate a xml file.
*/
XML,
}
48 changes: 33 additions & 15 deletions src/main/java/pl/project13/core/PropertiesFileGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import pl.project13.core.util.BuildFileChangeListener;
import pl.project13.core.util.JsonManager;
import pl.project13.core.util.PropertyManager;
import pl.project13.core.util.XmlManager;

import javax.annotation.Nonnull;
import java.io.*;
Expand Down Expand Up @@ -56,20 +57,27 @@ public void maybeGeneratePropertiesFile(
) throws GitCommitIdExecutionException {
try {
final File gitPropsFile = craftPropertiesOutputFile(projectDir, propsFile);
final boolean isJsonFormat = CommitIdPropertiesOutputFormat.JSON.equals(propertiesOutputFormat);

boolean shouldGenerate = true;

if (gitPropsFile.exists()) {
final Properties persistedProperties;

try {
if (isJsonFormat) {
log.info(String.format("Reading existing json file [%s] (for module %s)...", gitPropsFile.getAbsolutePath(), projectName));
persistedProperties = JsonManager.readJsonProperties(gitPropsFile, sourceCharset);
} else {
log.info(String.format("Reading existing properties file [%s] (for module %s)...", gitPropsFile.getAbsolutePath(), projectName));
persistedProperties = PropertyManager.readProperties(gitPropsFile);
switch (propertiesOutputFormat) {
case JSON:
log.info(String.format("Reading existing json file [%s] (for module %s)...", gitPropsFile.getAbsolutePath(), projectName));
persistedProperties = JsonManager.readJsonProperties(gitPropsFile, sourceCharset);
break;
case PROPERTIES:
log.info(String.format("Reading existing properties file [%s] (for module %s)...", gitPropsFile.getAbsolutePath(), projectName));
persistedProperties = PropertyManager.readProperties(gitPropsFile);
break;
case XML:
log.info(String.format("Reading existing xml file [%s] (for module %s)...", gitPropsFile.getAbsolutePath(), projectName));
persistedProperties = XmlManager.readXmlProperties(gitPropsFile, sourceCharset);
break;
default:
throw new GitCommitIdExecutionException("Not implemented:" + propertiesOutputFormat);
}

final Properties propertiesCopy = (Properties) localProperties.clone();
Expand All @@ -92,13 +100,23 @@ public void maybeGeneratePropertiesFile(
try (OutputStream outputStream = new FileOutputStream(gitPropsFile)) {
OrderedProperties sortedLocalProperties = PropertiesFileGenerator.createOrderedProperties();
localProperties.forEach((key, value) -> sortedLocalProperties.setProperty((String) key, (String) value));
if (isJsonFormat) {
log.info(String.format("Writing json file to [%s] (for module %s)...", gitPropsFile.getAbsolutePath(), projectName));
JsonManager.dumpJson(outputStream, sortedLocalProperties, sourceCharset);
} else {
log.info(String.format("Writing properties file to [%s] (for module %s)...", gitPropsFile.getAbsolutePath(), projectName));
// using outputStream directly instead of outputWriter this way the UTF-8 characters appears in unicode escaped form
PropertyManager.dumpProperties(outputStream, sortedLocalProperties, escapeUnicode);
switch (propertiesOutputFormat) {
case JSON:
log.info(String.format("Writing json file to [%s] (for module %s)...", gitPropsFile.getAbsolutePath(), projectName));
JsonManager.dumpJson(outputStream, sortedLocalProperties, sourceCharset);
break;
case PROPERTIES:
log.info(String.format("Writing properties file to [%s] (for module %s)...", gitPropsFile.getAbsolutePath(), projectName));
// using outputStream directly instead of outputWriter this way the UTF-8 characters appears in unicode escaped form
PropertyManager.dumpProperties(outputStream, sortedLocalProperties, escapeUnicode);
break;
case XML:
log.info(String.format("Writing xml file to [%s] (for module %s)...", gitPropsFile.getAbsolutePath(), projectName));
// using outputStream directly instead of outputWriter this way the UTF-8 characters appears in unicode escaped form
XmlManager.dumpXml(outputStream, sortedLocalProperties, sourceCharset);
break;
default:
throw new GitCommitIdExecutionException("Not implemented:" + propertiesOutputFormat);
}
} catch (final IOException ex) {
throw new RuntimeException("Cannot create custom git properties file: " + gitPropsFile, ex);
Expand Down
113 changes: 113 additions & 0 deletions src/main/java/pl/project13/core/util/XmlManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* This file is part of git-commit-id-plugin-core by Konrad 'ktoso' Malawski <[email protected]>
*
* git-commit-id-plugin-core is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* git-commit-id-plugin-core is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with git-commit-id-plugin-core. If not, see <http://www.gnu.org/licenses/>.
*/

package pl.project13.core.util;

import nu.studer.java.util.OrderedProperties;
import pl.project13.core.CannotReadFileException;

import javax.annotation.Nonnull;
import javax.xml.XMLConstants;
import javax.xml.stream.*;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Properties;

public class XmlManager {
public static void dumpXml(OutputStream outputStream, OrderedProperties sortedLocalProperties, Charset sourceCharset) throws IOException {
/*
TODO get rid of custom indents and use
https://ewernli.com/2009/06/18/stax-pretty-printer/
https://stackoverflow.com/a/38371920
*/
XMLOutputFactory fac = XMLOutputFactory.newInstance();

try (Writer outputWriter = new OutputStreamWriter(outputStream, sourceCharset)) {
XMLStreamWriter writer = fac.createXMLStreamWriter(outputWriter);
// <?xml version="1.0" encoding="UTF-8"?>
writer.writeStartDocument(StandardCharsets.UTF_8.toString(), "1.0");

writer.writeStartElement("gitCommitIdPlugin");
writer.writeCharacters("\n"); // indents

for (Map.Entry e : sortedLocalProperties.entrySet()) {
writer.writeCharacters(" "); // indents
// <property key="git.branch" value="master"/>
writer.writeEmptyElement("property");
writer.writeAttribute("key", e.getKey().toString());
writer.writeAttribute("value", e.getValue().toString());
writer.writeCharacters("\n"); // indents
}
writer.writeCharacters("\n"); // indents
writer.writeEndElement(); // </gitCommitIdPlugin>

writer.writeEndDocument();
writer.flush();
writer.close();
} catch (XMLStreamException e) {
throw new RuntimeException(e);
}

}

public static Properties readXmlProperties(@Nonnull File xmlFile, Charset sourceCharset) throws CannotReadFileException {
Properties retVal = new Properties();

try (FileInputStream fis = new FileInputStream(xmlFile)) {
try (InputStreamReader reader = new InputStreamReader(fis, sourceCharset)) {
XMLInputFactory factory = XMLInputFactory.newInstance();

// https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#Java
// factory.setProperty("http://apache.org/xml/features/disallow-doctype-decl", true); // not supported :/
// https://docs.oracle.com/en/java/javase/11/security/java-api-xml-processing-jaxp-security-guide.html#JSSEC-GUID-88B04BE2-35EF-4F61-B4FA-57A0E9102342
// Feature for Secure Processing (FSP)
// factory.setProperty(XMLConstants.FEATURE_SECURE_PROCESSING, true); // not supported :/
// https://rules.sonarsource.com/java/RSPEC-2755
// to be compliant, completely disable DOCTYPE declaration:
factory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
// or completely disable external entities declarations:
factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
// or prohibit the use of all protocols by external entities:
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");

// Other things we don't need
factory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, Boolean.FALSE);
factory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);

XMLStreamReader xmlReader = factory.createXMLStreamReader(reader);
while (xmlReader.hasNext()) {
if (xmlReader.next() == XMLStreamConstants.START_ELEMENT) {
if (xmlReader.getLocalName().equals("property")) {
String key = xmlReader.getAttributeValue(null, "key");
String value = xmlReader.getAttributeValue(null, "value");
retVal.setProperty(key, value);
}
}
}
} catch (XMLStreamException ex) {
throw new CannotReadFileException(ex);
}
} catch (IOException e) {
throw new CannotReadFileException(e);
}
return retVal;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.junit.runner.RunWith;
import pl.project13.core.git.GitDescribeConfig;
import pl.project13.core.util.JsonManager;
import pl.project13.core.util.XmlManager;

import javax.annotation.Nonnull;
import java.io.File;
Expand Down Expand Up @@ -460,8 +461,38 @@ public void shouldGenerateCustomPropertiesFileJson(boolean useNativeGit) throws
assertThat(targetFilePath).exists();
Properties p = JsonManager.readJsonProperties(targetFilePath, StandardCharsets.UTF_8);
assertThat(p.size() > 10);
Assert.assertEquals(p, properties);
}

@Test
@Parameters(method = "useNativeGit")
public void shouldGenerateCustomPropertiesFileXml(boolean useNativeGit) throws Exception {
// given
File dotGitDirectory = createTmpDotGitDirectory(AvailableGitTestRepo.WITH_ONE_COMMIT_WITH_SPECIAL_CHARACTERS);

File targetFilePath = sandbox.resolve("custom-git.xml").toFile();
targetFilePath.delete();

GitCommitIdPlugin.Callback cb =
new GitCommitIdTestCallback()
.setDotGitDirectory(dotGitDirectory)
.setUseNativeGit(useNativeGit)
.setShouldGenerateGitPropertiesFile(true)
.setGenerateGitPropertiesFilename(targetFilePath)
.setPropertiesOutputFormat(CommitIdPropertiesOutputFormat.XML)
.build();
Properties properties = new Properties();

// when
GitCommitIdPlugin.runPlugin(cb, properties);
// then
assertThat(targetFilePath).exists();
Properties p = XmlManager.readXmlProperties(targetFilePath, StandardCharsets.UTF_8);
assertThat(p.size() > 10);
Assert.assertEquals(p, properties);
}


@Test
@Parameters(method = "useNativeGit")
public void shouldGenerateDescribeWithTagOnlyWhenForceLongFormatIsFalse(boolean useNativeGit) throws Exception {
Expand Down

0 comments on commit 1d84b3d

Please sign in to comment.