Skip to content

Commit

Permalink
refs #43 - when adding a directory to the bag builder, it should keep…
Browse files Browse the repository at this point in the history
… the file path from that directory onward in the bag's tag directory. Also updated some tests to ensure unique temp directories
  • Loading branch information
jscancella committed Jul 23, 2020
1 parent b1e2fb7 commit 6865b5a
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 53 deletions.
106 changes: 63 additions & 43 deletions src/main/java/com/github/jscancella/domain/BagBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
Expand All @@ -24,21 +25,21 @@
/**
* Used to conveniently create a bag programmatically and incrementally
*/
@SuppressWarnings({"PMD.TooManyMethods", "PMD.BeanMembersShouldSerialize"})
@SuppressWarnings({ "PMD.TooManyMethods", "PMD.BeanMembersShouldSerialize" })
public final class BagBuilder {
private static final Logger logger = LoggerFactory.getLogger(BagBuilder.class);
private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle");

private Version specificationVersion = Version.LATEST_BAGIT_VERSION();
private Charset tagFilesEncoding = StandardCharsets.UTF_8;
private final Set<PathPair> payloadFiles = new HashSet<>();
private final Set<Path> tagFiles = new HashSet<>();
private final Set<String> bagitAlgorithmNames = new HashSet<>();
private final List<FetchItem> itemsToFetch = new ArrayList<>();
private final MetadataBuilder metadataBuilder = new MetadataBuilder();
//the current location of the bag on the filesystem
// the current location of the bag on the filesystem
private Path rootDir;

/**
* Set the bagit specification version
*
Expand All @@ -51,7 +52,7 @@ public BagBuilder version(final int major, final int minor) {
this.specificationVersion = new Version(major, minor);
return this;
}

/**
* Set the bagit specification version
*
Expand All @@ -62,19 +63,21 @@ public BagBuilder version(final Version version) {
this.specificationVersion = new Version(version.major, version.minor);
return this;
}

/**
* Set the tag file encoding. Defaults to UTF8
*
* @param fileEncoding the tag file encoding
* @return this builder so as to chain commands
*/
public BagBuilder fileEncoding(final Charset fileEncoding) {
this.tagFilesEncoding = Charset.forName(fileEncoding.name());
return this;
}

/**
* Add a file to the bag payload
*
* @param payload a file to add
* @return this builder so as to chain commands
*/
Expand All @@ -83,36 +86,42 @@ public BagBuilder addPayloadFile(final Path payload) {
this.addPayloadFile(payload.toAbsolutePath(), "data");
return this;
}

/**
* Add a file to the bag payload. The file will be written to the relative location to the bag root.
* @param payload the file to add
* @param relative the location in the bag for the file to be written. relative to the bag root directory.
* NOTE: the data directory MUST be included as this is part of the relative path
* Add a file to the bag payload. The file will be written to the relative
* location to the bag root.
*
* @param payload the file to add
* @param relative the location in the bag for the file to be written. relative
* to the bag root directory. NOTE: the data directory MUST be
* included as this is part of the relative path
* @return this builder so to chain commands
*/
public BagBuilder addPayloadFile(final Path payload, final String relative) {
this.payloadFiles.add(new PathPair(payload, relative));
return this;
}

/**
* Add a file to the bag tags
*
* @param tag a tag file to add
* @return this builder so as to chain commands
*/
public BagBuilder addTagFile(final Path tag) {
this.tagFiles.add(Paths.get(tag.toAbsolutePath().toString()));
return this;
}

/**
* add a bagit algorithm to use when computing the manifests
* @param bagitAlgorithmName the all lowercase name as specified in the bagit specification
*
* @param bagitAlgorithmName the all lowercase name as specified in the bagit
* specification
* @return this builder so as to chain commands
*/
public BagBuilder addAlgorithm(final String bagitAlgorithmName) {
if(BagitChecksumNameMapping.isSupported(bagitAlgorithmName)) {
if (BagitChecksumNameMapping.isSupported(bagitAlgorithmName)) {
this.bagitAlgorithmNames.add(bagitAlgorithmName);
}
else {
Expand All @@ -121,85 +130,96 @@ public BagBuilder addAlgorithm(final String bagitAlgorithmName) {
}
return this;
}

/**
* Add an item to fetch. These fetch items must be downloaded before the bag is complete
* Add an item to fetch. These fetch items must be downloaded before the bag is
* complete
*
* @param fetchItem an item to fetch
* @return this builder so as to chain commands
*/
public BagBuilder addItemToFetch(final FetchItem fetchItem) {
this.itemsToFetch.add(fetchItem);
return this;
}

/**
* Add a human understandable key value pair of information
* @param key metadata key
*
* @param key metadata key
* @param value metadata value
* @return this builder so as to chain commands
*/
public BagBuilder addMetadata(final String key, final String value) {
metadataBuilder.add(key, value);
return this;
}

/**
* Set the directory to use when creating a bag
*
* @param dir the root dir of a bag
* @return this builder so as to chain commands
*/
public BagBuilder bagLocation(final Path dir) {
this.rootDir = Paths.get(dir.toAbsolutePath().toString());
return this;
}

/**
* Write the bag out to a physical location (on disk)
*
* @return The bag that was created
* @throws IOException if there is a problem reading a file
*/
public Bag write() throws IOException{
if(rootDir == null) {
public Bag write() throws IOException {
if (rootDir == null) {
throw new InvalidBagStateException("Bags must have a root directory");
}

final Bag bag = new Bag(this.specificationVersion, this.tagFilesEncoding, createPayloadManifests(), createTagManifests(), this.itemsToFetch, metadataBuilder.build(), this.rootDir);


final Bag bag = new Bag(this.specificationVersion, this.tagFilesEncoding, createPayloadManifests(),
createTagManifests(), this.itemsToFetch, metadataBuilder.build(), this.rootDir);

return bag.write(this.rootDir);
}

@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
private Set<Manifest> createTagManifests() throws IOException{
@SuppressWarnings({"PMD.AvoidInstantiatingObjectsInLoops", "PMD.AvoidProtectedMethodInFinalClassNotExtending"})
protected Set<Manifest> createTagManifests() throws IOException {
final Set<Manifest> manifests = new HashSet<>();
for(final String name : bagitAlgorithmNames) {

for (final String name : bagitAlgorithmNames) {
final ManifestBuilder builder = new ManifestBuilder(name);

for(final Path tagFile : tagFiles) {
builder.addFile(tagFile, rootDir.relativize(rootDir));

for (final Path tagFile : tagFiles) {
if (Files.isDirectory(tagFile)) {
builder.addFile(tagFile, tagFile.getFileName());
}
else {
builder.addFile(tagFile, Paths.get(""));
}
}

manifests.add(builder.build());
}

return manifests;
}

@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
private Set<Manifest> createPayloadManifests() throws IOException{
private Set<Manifest> createPayloadManifests() throws IOException {
final Set<Manifest> manifests = new HashSet<>();
for(final String name : bagitAlgorithmNames) {

for (final String name : bagitAlgorithmNames) {
final ManifestBuilder builder = new ManifestBuilder(name);
for(final PathPair pair : payloadFiles) {
for (final PathPair pair : payloadFiles) {
final Path fullPathToNewLocation = rootDir.resolve(pair.getRelativeLocation());
final Path relativeToBaseDir = rootDir.relativize(fullPathToNewLocation);
builder.addFile(pair.getPayloadFile(), relativeToBaseDir);
}

manifests.add(builder.build());
}

return manifests;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ public ManifestBuilderVistor(final Path startingPoint, final Hasher hasher) {
@Override
public FileVisitResult visitFile(final Path path, final BasicFileAttributes attrs) throws IOException{
final Path physicalLocation = path.toAbsolutePath();
final Path relativeLocation = startingPoint.relativize(physicalLocation);
Path relativeStartingLocation = startingPoint.getParent();
if(relativeStartingLocation == null) {
relativeStartingLocation = startingPoint;
}
final Path relativeLocation = relativeStartingLocation.relativize(physicalLocation);
final String checksum = hasher.hash(physicalLocation);
final ManifestEntry entry = new ManifestEntry(physicalLocation, relativeLocation, checksum);

Expand Down
20 changes: 19 additions & 1 deletion src/test/java/com/github/jscancella/domain/BagBuilderTest.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.github.jscancella.domain;

import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Set;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -96,7 +98,7 @@ public void builderReturnsBagWhenWriting() throws Exception{
sut.addAlgorithm("md5");
sut.addMetadata("foo", "bar");
sut.addPayloadFile(Paths.get("src", "test", "resources", "md5Bag", "data", "readme.txt"));
sut.bagLocation(createDirectory("tempBag"));
sut.bagLocation(createDirectory("tempBagForWriting"));

Assertions.assertNotNull(sut.write());
}
Expand All @@ -106,4 +108,20 @@ public void builderThrowsErrorNonSupportedHashAlgorithm() {
BagBuilder sut = new BagBuilder();
Assertions.assertThrows(NoSuchBagitAlgorithmException.class, () -> { sut.addAlgorithm("somethingMadeUp"); });
}

@Test
public void builderHandlesAddingDirectoryAsTagFiles() throws IOException {
BagBuilder sut = new BagBuilder();
Path path = Paths.get("src", "test", "resources", "md5Bag", "data");
ManifestEntry expectedManifestEntry =
new ManifestEntry(path.resolve("readme.txt"), path.getFileName().resolve("readme.txt"), "aee452eebfbd978228775bf7b0e808dc");

sut.bagLocation(createDirectory("tempBagForTagFolderFiles"));
sut.addAlgorithm("md5");
sut.addTagFile(path);
Set<Manifest> tagManifests = sut.createTagManifests();
for(Manifest manifest : tagManifests) {
Assertions.assertTrue(manifest.getEntries().contains(expectedManifestEntry));
}
}
}
4 changes: 2 additions & 2 deletions src/test/java/com/github/jscancella/domain/BagTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void testReadObjectsAreEqual() throws Exception {
@Test
public void testLogicallySameObjectsAreEqual() throws Exception {
Path file = Paths.get("src", "test", "resources", "md5Bag", "bagit.txt");
Path folder = createDirectory("tempBag");
Path folder = createDirectory("tempBagAreEqual");

Bag bag = new BagBuilder().addAlgorithm("md5")
.addMetadata("foo", "bar")
Expand All @@ -45,7 +45,7 @@ public void testLogicallySameObjectsAreEqual() throws Exception {

@Test
public void testBagCreation() throws Exception{
Path rootDir = createDirectory("builtBag");
Path rootDir = createDirectory("tempBuiltBag");
Path payloadFile = Paths.get("src", "test", "resources", "bags", "v1_0", "bag", "data", "foo.txt");
Path tagFile = payloadFile;
FetchItem fetchItem = new FetchItem(new URI("https://hackaday.com"), 0l, Paths.get(""));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class BagitFileWriterTest extends TempFolderTest {

@Test
public void testWriteBagitFile() throws Exception{
Path rootDir = createDirectory("newFolder");
Path rootDir = createDirectory("testWriteBagitFile");
Path bagit = rootDir.resolve("bagit.txt");

Assertions.assertFalse(Files.exists(bagit));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class FetchWriterTest extends TempFolderTest {

@Test
public void testWriteFetchFile() throws Exception{
Path rootPath = createDirectory("fetchTest");
Path rootPath = createDirectory("testWriteFetchFile");
Path fetch = rootPath.resolve("fetch.txt");
URI uri = URI.create("http://localhost:/foo/bar");
List<FetchItem> itemsToFetch = Arrays.asList(new FetchItem(uri, -1l, rootPath.resolve("/data/foo/bar")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class ManifestWriterTest extends TempFolderTest {

@Test
public void testWritePayloadManifests() throws IOException {
Path outputFolder = createDirectory("write_payload_manifests");
Path outputFolder = createDirectory("testWritePayloadManifests");

ManifestBuilder builder = new ManifestBuilder("md5");
builder.addFile(Paths.get("src","test","resources","bags", "v1_0", "bag", "data", "foo.txt"), outputFolder.resolve("data"));
Expand All @@ -38,8 +38,7 @@ public void testWritePayloadManifests() throws IOException {

@Test
public void testWriteTagManifests() throws IOException{
//TODO
Path outputFolder = createDirectory("write_tag_manifests");
Path outputFolder = createDirectory("testWriteTagManifests");

ManifestBuilder builder = new ManifestBuilder("md5");
builder.addFile(Paths.get("src","test","resources","bags", "v1_0", "bag", "bagit.txt"), outputFolder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class MetadataWriterTest extends TempFolderTest {

@Test
public void testWriteBagitInfoFile() throws IOException{
Path rootDir = createDirectory("writeBagitInfo");
Path rootDir = createDirectory("testWriteBagitInfoFile");
Path bagInfo = rootDir.resolve("bag-info.txt");
Path packageInfo = rootDir.resolve("package-info.txt");
Metadata metadata = new MetadataBuilder()
Expand Down

0 comments on commit 6865b5a

Please sign in to comment.