diff --git a/src/main/java/com/github/jscancella/domain/BagBuilder.java b/src/main/java/com/github/jscancella/domain/BagBuilder.java index 40ebd38..ed22757 100644 --- a/src/main/java/com/github/jscancella/domain/BagBuilder.java +++ b/src/main/java/com/github/jscancella/domain/BagBuilder.java @@ -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; @@ -24,11 +25,11 @@ /** * 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 payloadFiles = new HashSet<>(); @@ -36,9 +37,9 @@ public final class BagBuilder { private final Set bagitAlgorithmNames = new HashSet<>(); private final List 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 * @@ -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 * @@ -62,9 +63,10 @@ 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 */ @@ -72,9 +74,10 @@ 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 */ @@ -83,21 +86,25 @@ 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 */ @@ -105,14 +112,16 @@ 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 { @@ -121,9 +130,11 @@ 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 */ @@ -131,10 +142,11 @@ 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 */ @@ -142,9 +154,10 @@ 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 */ @@ -152,54 +165,61 @@ 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 createTagManifests() throws IOException{ + @SuppressWarnings({"PMD.AvoidInstantiatingObjectsInLoops", "PMD.AvoidProtectedMethodInFinalClassNotExtending"}) + protected Set createTagManifests() throws IOException { final Set 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 createPayloadManifests() throws IOException{ + private Set createPayloadManifests() throws IOException { final Set 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; } } diff --git a/src/main/java/com/github/jscancella/domain/internal/ManifestBuilderVistor.java b/src/main/java/com/github/jscancella/domain/internal/ManifestBuilderVistor.java index fa55300..fd3287a 100644 --- a/src/main/java/com/github/jscancella/domain/internal/ManifestBuilderVistor.java +++ b/src/main/java/com/github/jscancella/domain/internal/ManifestBuilderVistor.java @@ -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); diff --git a/src/test/java/com/github/jscancella/domain/BagBuilderTest.java b/src/test/java/com/github/jscancella/domain/BagBuilderTest.java index 7adf0e8..fe601a2 100644 --- a/src/test/java/com/github/jscancella/domain/BagBuilderTest.java +++ b/src/test/java/com/github/jscancella/domain/BagBuilderTest.java @@ -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; @@ -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()); } @@ -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 tagManifests = sut.createTagManifests(); + for(Manifest manifest : tagManifests) { + Assertions.assertTrue(manifest.getEntries().contains(expectedManifestEntry)); + } + } } diff --git a/src/test/java/com/github/jscancella/domain/BagTest.java b/src/test/java/com/github/jscancella/domain/BagTest.java index 8a9a9e1..e72291d 100644 --- a/src/test/java/com/github/jscancella/domain/BagTest.java +++ b/src/test/java/com/github/jscancella/domain/BagTest.java @@ -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") @@ -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("")); diff --git a/src/test/java/com/github/jscancella/writer/internal/BagitFileWriterTest.java b/src/test/java/com/github/jscancella/writer/internal/BagitFileWriterTest.java index cb7f477..fc95553 100644 --- a/src/test/java/com/github/jscancella/writer/internal/BagitFileWriterTest.java +++ b/src/test/java/com/github/jscancella/writer/internal/BagitFileWriterTest.java @@ -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)); diff --git a/src/test/java/com/github/jscancella/writer/internal/FetchWriterTest.java b/src/test/java/com/github/jscancella/writer/internal/FetchWriterTest.java index 80e1fd9..c77da42 100644 --- a/src/test/java/com/github/jscancella/writer/internal/FetchWriterTest.java +++ b/src/test/java/com/github/jscancella/writer/internal/FetchWriterTest.java @@ -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 itemsToFetch = Arrays.asList(new FetchItem(uri, -1l, rootPath.resolve("/data/foo/bar")), diff --git a/src/test/java/com/github/jscancella/writer/internal/ManifestWriterTest.java b/src/test/java/com/github/jscancella/writer/internal/ManifestWriterTest.java index 6ed880c..8479796 100644 --- a/src/test/java/com/github/jscancella/writer/internal/ManifestWriterTest.java +++ b/src/test/java/com/github/jscancella/writer/internal/ManifestWriterTest.java @@ -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")); @@ -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); diff --git a/src/test/java/com/github/jscancella/writer/internal/MetadataWriterTest.java b/src/test/java/com/github/jscancella/writer/internal/MetadataWriterTest.java index 10dfc96..596948c 100644 --- a/src/test/java/com/github/jscancella/writer/internal/MetadataWriterTest.java +++ b/src/test/java/com/github/jscancella/writer/internal/MetadataWriterTest.java @@ -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()