diff --git a/src/Bag.php b/src/Bag.php index 332baf6..4473291 100644 --- a/src/Bag.php +++ b/src/Bag.php @@ -447,6 +447,10 @@ public function package(string $filepath): void if (!$this->isValid()) { throw new BagItException("Bag is not valid, cannot package."); } + $parent = dirname($filepath); + if (!is_dir($parent)) { + BagUtils::checkedMkdir($parent, 0777, true); + } $this->makePackage($filepath); } diff --git a/tests/BagTest.php b/tests/BagTest.php index 894ede0..0d9fd1d 100644 --- a/tests/BagTest.php +++ b/tests/BagTest.php @@ -761,6 +761,39 @@ public function testZipBag(): void ); } + /** + * Archive destinations may include directories that do not exist yet. + * + * @dataProvider nestedArchiveFormats + * @covers ::package + */ + public function testPackageCreatesParentDirectory(string $extension): void + { + mkdir($this->tmpdir); + $bag = Bag::create($this->tmpdir . "/bag"); + $bag->addFile(self::TEST_IMAGE['filename'], "data/image.jpg"); + $archive = $this->tmpdir . "/new/nested/archive." . $extension; + $this->assertDirectoryDoesNotExist(dirname($archive)); + $bag->package($archive); + $this->assertFileExists($archive); + $restored = Bag::load($archive); + try { + $this->assertTrue($restored->isValid()); + $this->assertSame( + $bag->getPayloadManifests()['sha512']->getHashes(), + $restored->getPayloadManifests()['sha512']->getHashes() + ); + } finally { + self::deleteDirAndContents(dirname($restored->getBagRoot())); + } + } + + /** @return array> */ + public static function nestedArchiveFormats(): array + { + return [['tar'], ['tar.gz'], ['tgz'], ['tar.bz2'], ['zip']]; + } + /** * Test generating a tar. *