Skip to content

Commit 4609560

Browse files
committed
Merge branch 'develop'
2 parents 6fcd159 + 7cca467 commit 4609560

File tree

8 files changed

+81
-12
lines changed

8 files changed

+81
-12
lines changed

changes.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@
2323
xsi:schemaLocation="http://maven.apache.org/changes/1.0.0 https://maven.apache.org/plugins/maven-changes-plugin/xsd/changes-1.0.0.xsd">
2424
<body>
2525

26+
<release version="1.7.4" date="2024-01-25">
27+
<action type="update" dev="sseifert" issue="2">
28+
Ensure folder path ZIP file entries are created.
29+
</action>
30+
</release>
31+
2632
<release version="1.7.2" date="2023-12-13">
2733
<action type="update" dev="sseifert">
2834
Switch to Java 11 as minimum version.

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@
2424
<parent>
2525
<groupId>io.wcm</groupId>
2626
<artifactId>io.wcm.parent_toplevel</artifactId>
27-
<version>2.2.6</version>
27+
<version>2.2.8</version>
2828
<relativePath />
2929
</parent>
3030

3131
<groupId>io.wcm.tooling.commons</groupId>
3232
<artifactId>io.wcm.tooling.commons.content-package-builder</artifactId>
33-
<version>1.7.2</version>
33+
<version>1.7.4</version>
3434
<packaging>jar</packaging>
3535

3636
<name>AEM Content Package Builder</name>
@@ -48,7 +48,7 @@
4848
<site.url.module.prefix>tooling/commons/content-package-builder</site.url.module.prefix>
4949

5050
<!-- Enable reproducible builds -->
51-
<project.build.outputTimestamp>2023-12-13T11:47:09Z</project.build.outputTimestamp>
51+
<project.build.outputTimestamp>2024-01-25T16:12:55Z</project.build.outputTimestamp>
5252
</properties>
5353

5454
<dependencies>

src/main/java/io/wcm/tooling/commons/contentpackagebuilder/ContentPackage.java

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@
3636
import java.io.InputStream;
3737
import java.io.OutputStream;
3838
import java.nio.charset.StandardCharsets;
39+
import java.util.HashSet;
3940
import java.util.List;
4041
import java.util.Map;
4142
import java.util.Objects;
4243
import java.util.Properties;
44+
import java.util.Set;
4345
import java.util.zip.ZipEntry;
4446
import java.util.zip.ZipOutputStream;
4547

@@ -51,10 +53,12 @@
5153
import javax.xml.transform.dom.DOMSource;
5254
import javax.xml.transform.stream.StreamResult;
5355

56+
import org.apache.commons.io.FilenameUtils;
5457
import org.apache.commons.io.IOUtils;
5558
import org.apache.commons.lang3.StringUtils;
5659
import org.apache.jackrabbit.vault.packaging.PackageProperties;
5760
import org.apache.jackrabbit.vault.util.PlatformNameFormat;
61+
import org.jetbrains.annotations.NotNull;
5862
import org.w3c.dom.Document;
5963

6064
import io.wcm.tooling.commons.contentpackagebuilder.ContentFolderSplitter.ContentPart;
@@ -71,13 +75,15 @@ public final class ContentPackage implements Closeable {
7175
private final ZipOutputStream zip;
7276
private final Transformer transformer;
7377
private final XmlContentBuilder xmlContentBuilder;
78+
private final Set<String> folderPaths = new HashSet<>();
7479

7580
private static final String CONTENT_TYPE_CHARSET_EXTENSION = ";charset=";
7681
private static final String DOT_DIR_FOLDER = ".dir";
7782

7883
/**
7984
* @param os Output stream
8085
*/
86+
@SuppressWarnings("java:S1141") // nested try-catch
8187
ContentPackage(PackageMetadata metadata, OutputStream os) throws IOException {
8288
this.metadata = metadata;
8389
this.zip = new ZipOutputStream(os);
@@ -107,7 +113,7 @@ public final class ContentPackage implements Closeable {
107113
}
108114
}
109115
catch (TransformerException ex) {
110-
throw new RuntimeException("Failed to set up XML transformer: " + ex.getMessage(), ex);
116+
throw new IllegalStateException("Failed to set up XML transformer: " + ex.getMessage(), ex);
111117
}
112118

113119
this.xmlContentBuilder = new XmlContentBuilder(metadata.getXmlNamespaces());
@@ -322,7 +328,7 @@ private void buildPackageMetadata() throws IOException {
322328
// package thumbnail
323329
byte[] thumbnailImage = metadata.getThumbnailImage();
324330
if (thumbnailImage != null) {
325-
zip.putNextEntry(new ZipEntry(META_DIR + "/definition/thumbnail.png"));
331+
zipPutNextFileEntry(META_DIR + "/definition/thumbnail.png");
326332
try {
327333
zip.write(thumbnailImage);
328334
}
@@ -345,7 +351,7 @@ private void buildTemplatedMetadataFile(String path) throws IOException {
345351
xmlContent = StringUtils.replace(xmlContent, "{{" + entry.getKey() + "}}",
346352
org.apache.commons.lang3.StringEscapeUtils.escapeXml10(entry.getValue().toString()));
347353
}
348-
zip.putNextEntry(new ZipEntry(path));
354+
zipPutNextFileEntry(path);
349355
try {
350356
zip.write(xmlContent.getBytes(StandardCharsets.UTF_8));
351357
}
@@ -372,7 +378,7 @@ private void buildPropertiesFile(String path) throws IOException {
372378
}
373379
}
374380

375-
zip.putNextEntry(new ZipEntry(path));
381+
zipPutNextFileEntry(path);
376382
try {
377383
properties.storeToXML(zip, null);
378384
}
@@ -388,7 +394,7 @@ private void buildPropertiesFile(String path) throws IOException {
388394
* @throws IOException I/O exception
389395
*/
390396
private void writeXmlDocument(String path, Document doc) throws IOException {
391-
zip.putNextEntry(new ZipEntry(path));
397+
zipPutNextFileEntry(path);
392398
try {
393399
DOMSource source = new DOMSource(doc);
394400
StreamResult result = new StreamResult(zip);
@@ -409,7 +415,7 @@ private void writeXmlDocument(String path, Document doc) throws IOException {
409415
* @throws IOException I/O exception
410416
*/
411417
private void writeBinaryFile(String path, InputStream is) throws IOException {
412-
zip.putNextEntry(new ZipEntry(path));
418+
zipPutNextFileEntry(path);
413419
try {
414420
IOUtils.copy(is, zip);
415421
}
@@ -418,4 +424,34 @@ private void writeBinaryFile(String path, InputStream is) throws IOException {
418424
}
419425
}
420426

427+
/**
428+
* Creates a new ZIP entry for a file with given paths.
429+
* Ensures that entries for the parent folders are created before.
430+
* @param path File path
431+
* @throws IOException I/O exception
432+
*/
433+
private void zipPutNextFileEntry(@NotNull String path) throws IOException {
434+
String folderPath = FilenameUtils.getPath(path);
435+
ensureFolderPaths(folderPath);
436+
zip.putNextEntry(new ZipEntry(path));
437+
}
438+
439+
/**
440+
* Ensures that zip entries for the given folder and it's parend folders (if they do not exist already).
441+
* @param folderPath Folder path
442+
* @throws IOException I/O exception
443+
*/
444+
private void ensureFolderPaths(@NotNull String folderPath) throws IOException {
445+
if (folderPaths.contains(folderPath) || StringUtils.isEmpty(folderPath) || StringUtils.equals(folderPath, "/")) {
446+
// skip paths already created and root folder
447+
return;
448+
}
449+
// ensure parent folders
450+
String parentFolderPath = FilenameUtils.getPath(StringUtils.removeEnd(folderPath, "/"));
451+
ensureFolderPaths(parentFolderPath);
452+
// create folder ZIP entry
453+
zip.putNextEntry(new ZipEntry(folderPath));
454+
folderPaths.add(folderPath);
455+
}
456+
421457
}

src/main/java/io/wcm/tooling/commons/contentpackagebuilder/ValueConverter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public String toString(String propertyName, Object value) {
7373
lastPropertyType = values[i].getType();
7474
}
7575
else if (lastPropertyType != values[i].getType()) {
76-
throw new RuntimeException("Mixing different value types within array not allowed: " +
76+
throw new IllegalArgumentException("Mixing different value types within array not allowed: " +
7777
PropertyType.nameFromValue(lastPropertyType) + ", " + PropertyType.nameFromValue(values[i].getType())
7878
+ ", propertyName=" + propertyName + ", value=" + value);
7979
}
@@ -88,7 +88,7 @@ else if (lastPropertyType != values[i].getType()) {
8888
return DocViewProperty.format(prop);
8989
}
9090
catch (RepositoryException ex) {
91-
throw new RuntimeException("Unable to format property value (" + propertyName + "): " + value, ex);
91+
throw new IllegalStateException("Unable to format property value (" + propertyName + "): " + value, ex);
9292
}
9393
}
9494

src/main/java/io/wcm/tooling/commons/contentpackagebuilder/XmlContentBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ final class XmlContentBuilder {
5959
this.documentBuilder.setEntityResolver(new PropertiesEntityResolver());
6060
}
6161
catch (ParserConfigurationException ex) {
62-
throw new RuntimeException("Failed to set up XML document builder: " + ex.getMessage(), ex);
62+
throw new IllegalStateException("Failed to set up XML document builder: " + ex.getMessage(), ex);
6363
}
6464
this.xmlNamespaces = xmlNamespaces;
6565
}

src/test/java/io/wcm/tooling/commons/contentpackagebuilder/ContentPackageBuilderTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import static org.junit.jupiter.api.Assertions.assertEquals;
2727
import static org.junit.jupiter.api.Assertions.assertNotNull;
2828
import static org.junit.jupiter.api.Assertions.assertThrows;
29+
import static org.junit.jupiter.api.Assertions.assertTrue;
2930

3031
import java.io.ByteArrayInputStream;
3132
import java.io.File;
@@ -39,9 +40,11 @@
3940
import org.junit.jupiter.api.Test;
4041
import org.junit.jupiter.api.TestInfo;
4142
import org.w3c.dom.Document;
43+
import org.zeroturnaround.zip.ZipUtil;
4244

4345
import io.wcm.tooling.commons.contentpackagebuilder.element.ContentElementImpl;
4446

47+
@SuppressWarnings("java:S5778") // assert throws
4548
class ContentPackageBuilderTest {
4649

4750
private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
@@ -90,6 +93,10 @@ void testMetadata() throws Exception {
9093
assertEquals("/content/mypath", contentPackage.getRootPath());
9194
}
9295

96+
ensureFolder("META-INF/");
97+
ensureFolder("META-INF/vault/");
98+
ensureFolder("META-INF/vault/definition/");
99+
93100
// validate metadata files
94101
Document configXml = getXmlFromZip("META-INF/vault/config.xml");
95102
assertXpathEvaluatesTo("1.1", "/vaultfs/@version", configXml);
@@ -132,6 +139,11 @@ void testAddPagesContentElement() throws Exception {
132139
contentPackage.addPage("/content/ns:page2", new ContentElementImpl(null, Map.of("var2", "v2")));
133140
}
134141

142+
ensureFolder("jcr_root/");
143+
ensureFolder("jcr_root/content/");
144+
ensureFolder("jcr_root/content/page1/");
145+
ensureFolder("jcr_root/content/_ns_page2/");
146+
135147
// validate resulting XML
136148
Document page1Xml = getXmlFromZip("jcr_root/content/page1/.content.xml");
137149
assertXpathEvaluatesTo("v1", "/jcr:root/jcr:content/@var1", page1Xml);
@@ -150,6 +162,11 @@ void testAddPages() throws Exception {
150162
contentPackage.addPage("/content/ns:page2", Map.of("var2", "v2"));
151163
}
152164

165+
ensureFolder("jcr_root/");
166+
ensureFolder("jcr_root/content/");
167+
ensureFolder("jcr_root/content/page1/");
168+
ensureFolder("jcr_root/content/_ns_page2/");
169+
153170
// validate resulting XML
154171
Document page1Xml = getXmlFromZip("jcr_root/content/page1/.content.xml");
155172
assertXpathEvaluatesTo("v1", "/jcr:root/jcr:content/@var1", page1Xml);
@@ -292,6 +309,9 @@ void testAddBinaries() throws Exception {
292309

293310
}
294311

312+
ensureFolder("jcr_root/");
313+
ensureFolder("jcr_root/content/");
314+
295315
// validate resulting files
296316
assertArrayEquals(data1, getDataFromZip("jcr_root/content/file1.txt"));
297317
Document metaXml = getXmlFromZip("jcr_root/content/file1.txt.dir/.content.xml");
@@ -308,4 +328,9 @@ private byte[] getDataFromZip(String path) throws Exception {
308328
private Document getXmlFromZip(String path) throws Exception {
309329
return ContentPackageTestUtil.getXmlFromZip(testFile, path);
310330
}
331+
332+
private void ensureFolder(String path) throws Exception {
333+
assertTrue(ZipUtil.containsEntry(testFile, path), "Folder exists: " + path);
334+
}
335+
311336
}

src/test/java/io/wcm/tooling/commons/contentpackagebuilder/ValueConverterTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.junit.jupiter.api.BeforeEach;
3434
import org.junit.jupiter.api.Test;
3535

36+
@SuppressWarnings("java:S5778") // assert throws
3637
class ValueConverterTest {
3738

3839
private ValueConverter underTest;

src/test/java/io/wcm/tooling/commons/contentpackagebuilder/XmlContentBuilderTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import io.wcm.tooling.commons.contentpackagebuilder.element.ContentElement;
3535
import io.wcm.tooling.commons.contentpackagebuilder.element.ContentElementImpl;
3636

37+
@SuppressWarnings("java:S5778") // assert throws
3738
class XmlContentBuilderTest {
3839

3940
private XmlContentBuilder underTest;

0 commit comments

Comments
 (0)