Skip to content

Commit b5ba581

Browse files
committed
Support recursive payload directory removal
1 parent 2b5244d commit b5ba581

2 files changed

Lines changed: 47 additions & 7 deletions

File tree

src/bagit/__init__.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -577,23 +577,31 @@ def add_payload(self, src, dest=None, processes=1):
577577
self.update_payload(processes=processes)
578578

579579

580-
def remove_payload(self, path, processes=1):
580+
def remove_payload(self, path, processes=1, recursive=False):
581581
"""
582582
Remove a payload file and rebuild manifests.
583583
"""
584-
payload_path = os.path.join(self.path, path)
584+
payload_path = os.path.normpath(path)
585585

586-
if not path.startswith("data" + os.sep):
586+
if self._path_is_dangerous(payload_path):
587+
raise ValueError("Payload path is unsafe: %s" % path)
588+
589+
if not payload_path.startswith("data" + os.sep):
587590
raise ValueError("Payload path must start with data/: %s" % path)
588591

589-
if not os.path.isfile(payload_path):
590-
raise ValueError("Payload path must be a file: %s" % path)
592+
full_path = os.path.join(self.path, payload_path)
591593

592-
os.remove(payload_path)
594+
if os.path.isfile(full_path):
595+
os.remove(full_path)
596+
elif os.path.isdir(full_path):
597+
if not recursive:
598+
raise ValueError("Payload path is a directory: %s" % path)
599+
shutil.rmtree(full_path)
600+
else:
601+
raise ValueError("Payload path does not exist: %s" % path)
593602

594603
self.update_payload(processes=processes)
595604

596-
597605
def tagfile_entries(self):
598606
return dict(
599607
(key, value)

test.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,6 +1178,38 @@ def test_add_payload_rejects_unsafe_destination(self):
11781178
with self.assertRaises(ValueError):
11791179
bag.add_payload(extra, "../extra.txt")
11801180

1181+
def test_remove_payload_directory_recursive(self):
1182+
bag = bagit.make_bag(self.tmpdir)
1183+
1184+
payload_dir = j(self.tmpdir, "data", "extra")
1185+
os.makedirs(payload_dir)
1186+
1187+
with open(j(payload_dir, "one.txt"), "w") as f:
1188+
f.write("one")
1189+
1190+
with open(j(payload_dir, "two.txt"), "w") as f:
1191+
f.write("two")
1192+
1193+
bag.update_payload()
1194+
self.assertTrue(bag.is_valid())
1195+
1196+
bag.remove_payload("data/extra", recursive=True)
1197+
1198+
bag = bagit.Bag(self.tmpdir)
1199+
1200+
self.assertFalse(os.path.exists(payload_dir))
1201+
self.assertTrue(bag.is_valid())
1202+
1203+
def test_remove_payload_directory_requires_recursive(self):
1204+
bag = bagit.make_bag(self.tmpdir)
1205+
1206+
payload_dir = j(self.tmpdir, "data", "extra")
1207+
os.makedirs(payload_dir)
1208+
1209+
with self.assertRaises(ValueError):
1210+
bag.remove_payload("data/extra")
1211+
1212+
11811213

11821214
class TestFetch(SelfCleaningTestCase):
11831215
def setUp(self):

0 commit comments

Comments
 (0)