Skip to content

Commit

Permalink
Ensure folder path ZIP file entries are created (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanseifert authored Jan 18, 2024
1 parent f3ee4ce commit 5a73cb5
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 5 deletions.
3 changes: 3 additions & 0 deletions changes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
<body>

<release version="1.7.4" date="not released">
<action type="update" dev="sseifert" issue="2">
Ensure folder path ZIP file entries are created.
</action>
<action type="update" dev="sseifert">
Switch to AEM 6.5.17 as minimum version.
</action>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

Expand All @@ -51,10 +53,12 @@
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jackrabbit.vault.packaging.PackageProperties;
import org.apache.jackrabbit.vault.util.PlatformNameFormat;
import org.jetbrains.annotations.NotNull;
import org.w3c.dom.Document;

import io.wcm.tooling.commons.contentpackagebuilder.ContentFolderSplitter.ContentPart;
Expand All @@ -71,6 +75,7 @@ public final class ContentPackage implements Closeable {
private final ZipOutputStream zip;
private final Transformer transformer;
private final XmlContentBuilder xmlContentBuilder;
private final Set<String> folderPaths = new HashSet<>();

private static final String CONTENT_TYPE_CHARSET_EXTENSION = ";charset=";
private static final String DOT_DIR_FOLDER = ".dir";
Expand Down Expand Up @@ -322,7 +327,7 @@ private void buildPackageMetadata() throws IOException {
// package thumbnail
byte[] thumbnailImage = metadata.getThumbnailImage();
if (thumbnailImage != null) {
zip.putNextEntry(new ZipEntry(META_DIR + "/definition/thumbnail.png"));
zipPutNextFileEntry(META_DIR + "/definition/thumbnail.png");
try {
zip.write(thumbnailImage);
}
Expand All @@ -345,7 +350,7 @@ private void buildTemplatedMetadataFile(String path) throws IOException {
xmlContent = StringUtils.replace(xmlContent, "{{" + entry.getKey() + "}}",
org.apache.commons.lang3.StringEscapeUtils.escapeXml10(entry.getValue().toString()));
}
zip.putNextEntry(new ZipEntry(path));
zipPutNextFileEntry(path);
try {
zip.write(xmlContent.getBytes(StandardCharsets.UTF_8));
}
Expand All @@ -372,7 +377,7 @@ private void buildPropertiesFile(String path) throws IOException {
}
}

zip.putNextEntry(new ZipEntry(path));
zipPutNextFileEntry(path);
try {
properties.storeToXML(zip, null);
}
Expand All @@ -388,7 +393,7 @@ private void buildPropertiesFile(String path) throws IOException {
* @throws IOException I/O exception
*/
private void writeXmlDocument(String path, Document doc) throws IOException {
zip.putNextEntry(new ZipEntry(path));
zipPutNextFileEntry(path);
try {
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(zip);
Expand All @@ -409,7 +414,7 @@ private void writeXmlDocument(String path, Document doc) throws IOException {
* @throws IOException I/O exception
*/
private void writeBinaryFile(String path, InputStream is) throws IOException {
zip.putNextEntry(new ZipEntry(path));
zipPutNextFileEntry(path);
try {
IOUtils.copy(is, zip);
}
Expand All @@ -418,4 +423,34 @@ private void writeBinaryFile(String path, InputStream is) throws IOException {
}
}

/**
* Creates a new ZIP entry for a file with given paths.
* Ensures that entries for the parent folders are created before.
* @param path File path
* @throws IOException I/O exception
*/
private void zipPutNextFileEntry(@NotNull String path) throws IOException {
String folderPath = FilenameUtils.getPath(path);
ensureFolderPaths(folderPath);
zip.putNextEntry(new ZipEntry(path));
}

/**
* Ensures that zip entries for the given folder and it's parend folders (if they do not exist already).
* @param folderPath Folder path
* @throws IOException I/O exception
*/
private void ensureFolderPaths(@NotNull String folderPath) throws IOException {
if (folderPaths.contains(folderPath) || StringUtils.isEmpty(folderPath) || StringUtils.equals(folderPath, "/")) {
// skip paths already created and root folder
return;
}
// ensure parent folders
String parentFolderPath = FilenameUtils.getPath(StringUtils.removeEnd(folderPath, "/"));
ensureFolderPaths(parentFolderPath);
// create folder ZIP entry
zip.putNextEntry(new ZipEntry(folderPath));
folderPaths.add(folderPath);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.ByteArrayInputStream;
import java.io.File;
Expand All @@ -39,6 +40,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.w3c.dom.Document;
import org.zeroturnaround.zip.ZipUtil;

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

Expand Down Expand Up @@ -90,6 +92,10 @@ void testMetadata() throws Exception {
assertEquals("/content/mypath", contentPackage.getRootPath());
}

ensureFolder("META-INF/");
ensureFolder("META-INF/vault/");
ensureFolder("META-INF/vault/definition/");

// validate metadata files
Document configXml = getXmlFromZip("META-INF/vault/config.xml");
assertXpathEvaluatesTo("1.1", "/vaultfs/@version", configXml);
Expand Down Expand Up @@ -132,6 +138,11 @@ void testAddPagesContentElement() throws Exception {
contentPackage.addPage("/content/ns:page2", new ContentElementImpl(null, Map.of("var2", "v2")));
}

ensureFolder("jcr_root/");
ensureFolder("jcr_root/content/");
ensureFolder("jcr_root/content/page1/");
ensureFolder("jcr_root/content/_ns_page2/");

// validate resulting XML
Document page1Xml = getXmlFromZip("jcr_root/content/page1/.content.xml");
assertXpathEvaluatesTo("v1", "/jcr:root/jcr:content/@var1", page1Xml);
Expand All @@ -150,6 +161,11 @@ void testAddPages() throws Exception {
contentPackage.addPage("/content/ns:page2", Map.of("var2", "v2"));
}

ensureFolder("jcr_root/");
ensureFolder("jcr_root/content/");
ensureFolder("jcr_root/content/page1/");
ensureFolder("jcr_root/content/_ns_page2/");

// validate resulting XML
Document page1Xml = getXmlFromZip("jcr_root/content/page1/.content.xml");
assertXpathEvaluatesTo("v1", "/jcr:root/jcr:content/@var1", page1Xml);
Expand Down Expand Up @@ -292,6 +308,9 @@ void testAddBinaries() throws Exception {

}

ensureFolder("jcr_root/");
ensureFolder("jcr_root/content/");

// validate resulting files
assertArrayEquals(data1, getDataFromZip("jcr_root/content/file1.txt"));
Document metaXml = getXmlFromZip("jcr_root/content/file1.txt.dir/.content.xml");
Expand All @@ -308,4 +327,9 @@ private byte[] getDataFromZip(String path) throws Exception {
private Document getXmlFromZip(String path) throws Exception {
return ContentPackageTestUtil.getXmlFromZip(testFile, path);
}

private void ensureFolder(String path) throws Exception {
assertTrue(ZipUtil.containsEntry(testFile, path), "Folder exists: " + path);
}

}

0 comments on commit 5a73cb5

Please sign in to comment.