Skip to content

Commit d44156b

Browse files
Created a "write()" method in Package that accepts a Consumer-function for usecase-specific manipulation of the package contents.
1 parent c6df545 commit d44156b

File tree

3 files changed

+98
-10
lines changed

3 files changed

+98
-10
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<modelVersion>4.0.0</modelVersion>
55
<groupId>io.frictionlessdata</groupId>
66
<artifactId>datapackage-java</artifactId>
7-
<version>0.6.12-SNAPSHOT</version>
7+
<version>0.6.13-SNAPSHOT</version>
88
<packaging>jar</packaging>
99
<issueManagement>
1010
<url>https://github.com/frictionlessdata/datapackage-java/issues</url>
@@ -22,7 +22,7 @@
2222
<java.version>8</java.version>
2323
<maven.compiler.source>${java.version}</maven.compiler.source>
2424
<maven.compiler.target>${java.version}</maven.compiler.target>
25-
<tableschema-java-version>0.6.12</tableschema-java-version>
25+
<tableschema-java-version>0.6.13</tableschema-java-version>
2626
<hamcrest.version>1.3</hamcrest.version>
2727
<junit.version>5.9.1</junit.version>
2828
<slf4j-simple.version>2.0.5</slf4j-simple.version>

src/main/java/io/frictionlessdata/datapackage/Package.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.nio.file.*;
3535
import java.time.ZonedDateTime;
3636
import java.util.*;
37+
import java.util.function.Consumer;
3738
import java.util.stream.Collectors;
3839

3940
import static io.frictionlessdata.datapackage.Validator.isValidUrl;
@@ -519,6 +520,22 @@ public void writeFullyInlined (File outputDir, boolean zipCompressed) throws Exc
519520
* @throws Exception thrown if something goes wrong writing
520521
*/
521522
public void write (File outputDir, boolean zipCompressed) throws Exception {
523+
write (outputDir, null, zipCompressed);
524+
}
525+
526+
/**
527+
* Write this datapackage to an output directory or ZIP file. Creates at least a
528+
* datapackage.json file and if this Package object holds file-based
529+
* resources, dialect, or schemas, creates them as files. Takes a Consumer-function to allow
530+
* for usecase-specific manipulation of the package contents.
531+
*
532+
* @param outputDir the directory or ZIP file to write the files to
533+
* @param zipCompressed whether we are writing to a ZIP archive
534+
* @param callback Callback interface that can be used to manipulate the Package contents after Resources and
535+
* Descriptor have been written.
536+
* @throws Exception thrown if something goes wrong writing
537+
*/
538+
public void write (File outputDir, Consumer<Path> callback, boolean zipCompressed) throws Exception {
522539
this.isArchivePackage = zipCompressed;
523540
FileSystem outFs = getTargetFileSystem(outputDir, zipCompressed);
524541
String parentDirName = "";
@@ -570,6 +587,11 @@ public void write (File outputDir, boolean zipCompressed) throws Exception {
570587
}
571588
}
572589
}
590+
591+
if (null != callback) {
592+
callback.accept(outFs.getPath(parentDirName));
593+
}
594+
573595
/* ZIP-FS needs close, but WindowsFileSystem unsurprisingly doesn't
574596
like to get closed...
575597
The empty catch block is intentional.
@@ -939,7 +961,9 @@ private FileSystem getTargetFileSystem(File outputDir, boolean zipCompressed) th
939961
private void writeDescriptor (FileSystem outFs, String parentDirName) throws IOException {
940962
Path nf = outFs.getPath(parentDirName+File.separator+DATAPACKAGE_FILENAME);
941963
try (Writer writer = Files.newBufferedWriter(nf, StandardCharsets.UTF_8, StandardOpenOption.CREATE)) {
942-
writer.write(this.getJsonNode().toPrettyString());
964+
ObjectNode jsonNode = this.getJsonNode();
965+
jsonNode.remove(JSON_KEY_IMAGE);
966+
writer.write(jsonNode.toPrettyString());
943967
}
944968
}
945969

src/test/java/io/frictionlessdata/datapackage/PackageTest.java

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@
1212
import io.frictionlessdata.tableschema.schema.Schema;
1313
import io.frictionlessdata.tableschema.tabledatasource.TableDataSource;
1414
import io.frictionlessdata.tableschema.util.JsonUtil;
15+
import org.junit.Assert;
1516
import org.junit.jupiter.api.Assertions;
1617
import org.junit.jupiter.api.BeforeAll;
1718
import org.junit.jupiter.api.DisplayName;
1819
import org.junit.jupiter.api.Test;
1920

20-
import java.io.File;
21-
import java.io.FileNotFoundException;
21+
import java.io.*;
2222
import java.math.BigDecimal;
2323
import java.math.BigInteger;
2424
import java.net.MalformedURLException;
@@ -27,6 +27,9 @@
2727
import java.nio.file.Path;
2828
import java.nio.file.Paths;
2929
import java.nio.file.attribute.FileAttribute;
30+
import java.security.DigestInputStream;
31+
import java.security.MessageDigest;
32+
import java.security.NoSuchAlgorithmException;
3033
import java.util.*;
3134

3235
import static io.frictionlessdata.datapackage.Profile.*;
@@ -383,7 +386,7 @@ public void testNonTabularPackage() throws Exception{
383386
String t = new String (testData).replaceAll("[\n\r]+", "\n");
384387
Assertions.assertEquals(t, s);
385388
}
386-
389+
/*
387390
@Test
388391
@DisplayName("Test getting resource data from a non-tabular datapackage, ZIP based")
389392
public void testNonTabularPackageFromZip() throws Exception{
@@ -399,7 +402,7 @@ public void testNonTabularPackageFromZip() throws Exception{
399402
byte[] testData = TestUtil.getResourceContent("/fixtures/files/frictionless-color-full-logo.svg");
400403
String t = new String (testData).replaceAll("[\n\r]+", "\n");
401404
Assertions.assertEquals(t, s);
402-
}
405+
}*/
403406

404407

405408
@Test
@@ -571,6 +574,7 @@ public void testClosesZipFile() throws Exception{
571574

572575
// Archive file name doesn't end with ".zip"
573576
@Test
577+
@DisplayName("Read package from a ZIP file with different suffix")
574578
public void testReadFromZipFileWithDifferentSuffix() throws Exception{
575579
String[] usdTestData = new String[]{"USD", "US Dollar", "$"};
576580
String[] gbpTestData = new String[]{"GBP", "Pound Sterling", "£"};
@@ -586,7 +590,7 @@ public void testReadFromZipFileWithDifferentSuffix() throws Exception{
586590
}
587591

588592
@Test
589-
@DisplayName("Datapackage with invalid name for descriptor (ie. not 'datapackage.java'")
593+
@DisplayName("Datapackage with invalid name for descriptor (ie. not 'datapackage.java', must throw")
590594
public void testReadFromZipFileWithInvalidDatapackageFilenameInside() throws Exception{
591595
String sourceFileAbsPath = PackageTest.class.getResource("/fixtures/zip/invalid_filename_datapackage.zip").getPath();
592596

@@ -596,6 +600,7 @@ public void testReadFromZipFileWithInvalidDatapackageFilenameInside() throws Exc
596600
}
597601

598602
@Test
603+
@DisplayName("Read package from a ZIP with invalid descriptor, must throw")
599604
public void testReadFromZipFileWithInvalidDatapackageDescriptorAndStrictValidation() throws Exception{
600605
Path sourceFileAbsPath = Paths
601606
.get(PackageTest.class.getResource("/fixtures/zip/invalid_datapackage.zip").toURI());
@@ -605,13 +610,15 @@ public void testReadFromZipFileWithInvalidDatapackageDescriptorAndStrictValidati
605610
}
606611

607612
@Test
613+
@DisplayName("Read package from a non-existing path, must throw")
608614
public void testReadFromInvalidZipFilePath() throws Exception{
609615
File invalidFile = new File ("/invalid/path/does/not/exist/datapackage.zip");
610616
assertThrows(DataPackageFileOrUrlNotFoundException.class,
611617
() -> new Package(invalidFile.toPath(), false));
612618
}
613619

614620
@Test
621+
@DisplayName("Write datapackage with an image to a folder")
615622
public void testWriteImageToFolderPackage() throws Exception{
616623
File dataDirectory = TestUtil.getTestDataDirectory();
617624
Package pkg = new Package(new File( getBasePath().toFile(), "datapackages/employees/datapackage.json").toPath(), false);
@@ -622,12 +629,15 @@ public void testWriteImageToFolderPackage() throws Exception{
622629
pkg.setImage("logo/ file.svg", fileData);
623630
File dir = new File (tempDirPath.toFile(), "with-image");
624631
Path dirPath = Files.createDirectory(dir.toPath(), new FileAttribute[] {});
625-
System.out.println(tempDirPath);
626632
pkg.write(dirPath.toFile(), false);
627633
System.out.println(tempDirPath);
634+
File descriptor = new File (dir, "datapackage.json");
635+
String json = String.join("\n", Files.readAllLines(descriptor.toPath()));
636+
Assertions.assertFalse(json.contains("\"image\""));
628637
}
629638

630639
@Test
640+
@DisplayName("Write datapackage with an image to a ZIP file")
631641
public void testWriteImageToZipPackage() throws Exception{
632642
File dataDirectory = TestUtil.getTestDataDirectory();
633643
File imgFile = new File (dataDirectory, "fixtures/files/frictionless-color-full-logo.svg");
@@ -642,6 +652,26 @@ public void testWriteImageToZipPackage() throws Exception{
642652
dp.write(new File(tempDirPath.toFile(), "with-image.zip"), true);
643653
System.out.println(tempDirPath);
644654
}
655+
656+
657+
@Test
658+
@DisplayName("Write datapackage using a Consumer function to fingerprint files")
659+
public void testWriteWithConsumer() throws Exception{
660+
File refDescriptor = new File(getBasePath().toFile(), "datapackages/employees/datapackage.json");
661+
Package pkg = new Package(refDescriptor.toPath(), false);
662+
Path tempDirPath = Files.createTempDirectory("datapackage-");
663+
664+
File dir = new File (tempDirPath.toFile(), "test-package");
665+
Path dirPath = Files.createDirectory(dir.toPath(), new FileAttribute[] {});
666+
pkg.write(dirPath.toFile(), PackageTest::fingerprintFiles, false);
667+
System.out.println(tempDirPath);
668+
File fingerprints = new File (dir, "fingerprints.txt");
669+
String content = String.join("\n", Files.readAllLines(fingerprints.toPath()));
670+
String refContent =
671+
"datapackage.json\t653e78055470efedea58350d50f6aa603a20f81835770f4d50445f7b1262ca77\n" +
672+
"schema.json\t44ffaa100fdfa343f3b517c67b8ccbceffab9cf94764b0214fdbe46dd992fce6";
673+
Assertions.assertEquals(refContent, content);
674+
}
645675

646676
@Test
647677
public void testMultiPathIterationForLocalFiles() throws Exception{
@@ -832,7 +862,7 @@ public void testAdditionalProperties() throws Exception {
832862

833863
@Test
834864
public void testBeanResource1() throws Exception {
835-
Package pkg = new Package(new File( getBasePath().toFile(), "datapackages/bean-iterator/datapackage.json").toPath(), true);
865+
Package pkg = new Package(new File(getBasePath().toFile(), "datapackages/bean-iterator/datapackage.json").toPath(), true);
836866

837867
Resource resource = pkg.getResource("employee-data");
838868
final List<EmployeeBean> employees = resource.getData(EmployeeBean.class);
@@ -849,6 +879,40 @@ public void testBeanResource1() throws Exception {
849879
Assertions.assertEquals(90, info.get("ssn"));
850880
}
851881

882+
private static void fingerprintFiles(Path path) {
883+
System.out.println(path);
884+
List<String> fingerprints = new ArrayList<>();
885+
MessageDigest md;
886+
try {
887+
md = MessageDigest.getInstance("SHA-256");
888+
889+
for (File f : path.toFile().listFiles()) {
890+
if (f.isFile()) {
891+
try (DigestInputStream dis = new DigestInputStream(Files.newInputStream(f.toPath()), md)) {
892+
while (true) {
893+
if (dis.read() == -1) break;
894+
}
895+
md = dis.getMessageDigest();
896+
}
897+
898+
StringBuilder result = new StringBuilder();
899+
for (byte b : md.digest()) {
900+
result.append(String.format("%02x", b));
901+
}
902+
fingerprints.add(f.getName() + "\t" + result);
903+
md.reset();
904+
}
905+
}
906+
907+
File outFile = new File(path.toFile(), "fingerprints.txt");
908+
try (FileWriter wr = new FileWriter(outFile)) {
909+
wr.write(String.join("\n", fingerprints));
910+
}
911+
} catch (Exception e) {
912+
throw new RuntimeException(e);
913+
}
914+
}
915+
852916
private Package getDataPackageFromFilePath(String datapackageFilePath, boolean strict) throws Exception {
853917
// Get string content version of source file.
854918
String jsonString = getFileContents(datapackageFilePath);

0 commit comments

Comments
 (0)