Skip to content

Commit a8c88b5

Browse files
author
Rakshil Modi
committed
Remove BucketLister class
Added change logs
1 parent cf2392e commit a8c88b5

File tree

8 files changed

+42
-94
lines changed

8 files changed

+42
-94
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"type": "enhancement",
3+
"category": "s3",
4+
"description": "Add all-versions flag with AWS CLI S3 rm command to delete all versions of objects present in a versioned-enabled bucket. fixes `#4070 <https://github.com/aws/aws-cli/issues/4070>`__"
5+
}

awscli/customizations/s3/filegenerator.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
from awscli.customizations.s3.utils import (
2424
EPOCH_TIME,
2525
BucketLister,
26-
BucketVersionLister,
2726
create_warning,
2827
find_bucket_key,
2928
find_dest_path_comp_key,
@@ -414,7 +413,7 @@ def _list_single_object(self, s3_path):
414413
class VersionedFileGenerator:
415414
"""
416415
This class generates VersionedFileInfo objects for all versions of objects in a bucket.
417-
It uses the BucketVersionLister to list all versions and creates appropriate
416+
It uses the BucketLister class to list all versions and creates appropriate
418417
VersionedFileInfo objects for each version.
419418
"""
420419

@@ -447,7 +446,7 @@ def __init__(
447446
self.request_parameters = {}
448447
if request_parameters is not None:
449448
self.request_parameters = request_parameters
450-
self._version_lister = BucketVersionLister(client)
449+
self._version_lister = BucketLister(client)
451450

452451
def call(self, files):
453452
"""
@@ -466,9 +465,6 @@ def call(self, files):
466465
for src_path, content, version_id in file_iterator:
467466
dest_path, compare_key = find_dest_path_comp_key(files, src_path)
468467

469-
# Check if this is a delete marker
470-
is_delete_marker = content.get('DeleteMarker', False)
471-
472468
# Create a VersionedFileInfo for this object version
473469
yield VersionedFileInfo(
474470
src=src_path,
@@ -479,10 +475,8 @@ def call(self, files):
479475
src_type=src_type,
480476
dest_type=dest_type,
481477
operation_name=self.operation_name,
482-
# client=self._client,
483478
associated_response_data=content,
484479
version_id=version_id,
485-
is_delete_marker=is_delete_marker,
486480
)
487481

488482
def list_object_versions(self, s3_path, dir_op):

awscli/customizations/s3/fileinfo.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,9 @@ def __init__(self, version_id=None, is_delete_marker=False, **kwargs):
120120
121121
:param version_id: The version ID of the S3 object.
122122
:type version_id: string
123-
:param is_delete_marker: Whether this version is a delete marker.
124-
:type is_delete_marker: boolean
125123
"""
126124
super().__init__(**kwargs)
127125
self.version_id = version_id
128-
self.is_delete_marker = is_delete_marker
129126

130127
def is_glacier_compatible(self):
131128
"""

awscli/customizations/s3/s3handler.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ def create_batches(self, fileinfos):
656656
for fileinfo in fileinfos:
657657
bucket, key = split_s3_bucket_key(fileinfo.src)
658658
obj_entry = {'Key': key}
659-
if hasattr(fileinfo, 'version_id') and fileinfo.version_id:
659+
if getattr(fileinfo, 'version_id', None):
660660
obj_entry['VersionId'] = fileinfo.version_id
661661

662662
objects_with_fileinfo.append(
@@ -836,14 +836,14 @@ def _submit_transfer_request_for_batch(self, batches):
836836

837837
# Report success
838838
for fileinfo in fileinfos_in_batch:
839-
self._report_sucess(fileinfo)
839+
self._report_success(fileinfo)
840840

841841
except Exception as e:
842842
for fileinfo in fileinfos_in_batch:
843843
self._report_failure(fileinfo, e)
844844
return total_objects
845845

846-
def _report_sucess(self, fileinfo):
846+
def _report_success(self, fileinfo):
847847
src, dest = self._format_src_dest(fileinfo)
848848
self._result_queue.put(
849849
SuccessResult(transfer_type='delete', src=src, dest=dest)

awscli/customizations/s3/subcommands.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1385,7 +1385,7 @@ def run(self):
13851385
self._map_request_payer_params(rgen_request_parameters)
13861386
rgen_kwargs['request_parameters'] = rgen_request_parameters
13871387

1388-
if self.parameters.get('all_versions'):
1388+
if self.cmd == 'rm' and self.parameters.get('all_versions'):
13891389
versioned_file_generator = VersionedFileGenerator(**fgen_kwargs)
13901390
file_generator = None
13911391
rev_generator = None

awscli/customizations/s3/utils.py

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -431,23 +431,6 @@ def list_objects(
431431
)
432432
yield source_path, content
433433

434-
435-
class BucketVersionLister:
436-
"""List object versions in a bucket
437-
This class provides functionality to list all versions of objects in a S3 bucket.
438-
It can list versions for a specific object (when prefix is provided) or for all
439-
objects in the bucket.
440-
"""
441-
442-
def __init__(self, client, date_parser=_date_parser):
443-
"""
444-
Initialize a new BucketVersionLister.
445-
:param client: The S3 client to use for listing versions.
446-
:param date_parser: A function to parse date strings into datetime objects.
447-
"""
448-
self._client = client
449-
self._date_parser = date_parser
450-
451434
def list_object_versions(
452435
self, bucket, prefix=None, page_size=None, extra_args=None
453436
):
@@ -479,25 +462,30 @@ def list_object_versions(
479462
paginator = self._client.get_paginator('list_object_versions')
480463
pages = paginator.paginate(**kwargs)
481464
for page in pages:
482-
# Process versions
483465
versions = page.get('Versions', [])
484-
for version in versions:
485-
source_path = bucket + '/' + version['Key']
486-
version['LastModified'] = self._date_parser(
487-
version['LastModified']
488-
)
489-
version['DeleteMarker'] = False
490-
yield source_path, version, version['VersionId']
491466

492-
# Process delete markers
467+
for (
468+
source_path,
469+
content,
470+
version_id,
471+
) in self._process_object_versions(bucket, versions):
472+
yield source_path, content, version_id
473+
493474
delete_markers = page.get('DeleteMarkers', [])
494-
for marker in delete_markers:
495-
source_path = bucket + '/' + marker['Key']
496-
marker['LastModified'] = self._date_parser(
497-
marker['LastModified']
498-
)
499-
marker['DeleteMarker'] = True
500-
yield source_path, marker, marker['VersionId']
475+
for (
476+
source_path,
477+
content,
478+
version_id,
479+
) in self._process_object_versions(bucket, delete_markers):
480+
yield source_path, content, version_id
481+
482+
def _process_object_versions(self, bucket, object_versions):
483+
for version in object_versions:
484+
source_path = bucket + '/' + version['Key']
485+
version['LastModified'] = self._date_parser(
486+
version['LastModified']
487+
)
488+
yield source_path, version, version['VersionId']
501489

502490

503491
class PrintTask(

tests/unit/customizations/s3/test_s3handler.py

Lines changed: 8 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,76 +1305,44 @@ def test_enqueue_batch_deletes(self):
13051305
fileinfos = []
13061306
num_transfers = 5
13071307
for i in range(num_transfers):
1308-
fileinfo = FileInfo(
1308+
fileinfo = VersionedFileInfo(
13091309
src=f'bucket/key{i}',
13101310
dest=None,
13111311
operation_name='delete',
13121312
src_type='s3',
1313+
version_id=f'version{i}',
13131314
)
1314-
fileinfo.version_id = f'version{i}'
13151315
fileinfos.append(fileinfo)
13161316

1317-
mock_submitter = mock.Mock()
1318-
mock_submitter.can_submit.return_value = True
1319-
mock_submitter.submit_batch.return_value = num_transfers
1320-
self.batch_s3_handler._batch_submitters = [mock_submitter]
1321-
1322-
self.batch_s3_handler.call(fileinfos)
1323-
mock_submitter.submit_batch.assert_called_once()
1317+
self.batch_s3_handler.call(iter(fileinfos))
1318+
self.transfer_manager.batch_delete.assert_called_once()
13241319

13251320
def test_notifies_total_submissions(self):
13261321
fileinfos = []
13271322
num_transfers = 5
13281323
for i in range(num_transfers):
1329-
fileinfo = FileInfo(
1324+
fileinfo = VersionedFileInfo(
13301325
src=f'bucket/key{i}',
13311326
dest=None,
13321327
operation_name='delete',
13331328
src_type='s3',
1329+
version_id=f'version{i}',
13341330
)
1335-
fileinfo.version_id = f'version{i}'
13361331
fileinfos.append(fileinfo)
13371332

1338-
# Mock the batch delete submitter
1339-
mock_submitter = mock.Mock()
1340-
mock_submitter.can_submit.return_value = True
1341-
mock_submitter.submit_batch.return_value = num_transfers
1342-
self.batch_s3_handler._batch_submitters = [mock_submitter]
1343-
1344-
self.batch_s3_handler.call(fileinfos)
1333+
self.batch_s3_handler.call(iter(fileinfos))
13451334
assert (
13461335
self.result_recorder.final_expected_files_transferred
13471336
== num_transfers
13481337
)
13491338

1350-
def test_call_selects_correct_submitter(self):
1351-
fileinfo = VersionedFileInfo(
1352-
src='bucket/key',
1353-
dest=None,
1354-
operation_name='delete',
1355-
src_type='s3',
1356-
version_id='version123',
1357-
)
1358-
1359-
mock_submitter = mock.Mock()
1360-
mock_submitter.can_submit.return_value = True
1361-
mock_submitter.submit_batch.return_value = 1
1362-
self.batch_s3_handler._batch_submitters = [mock_submitter]
1363-
1364-
self.batch_s3_handler.call([fileinfo])
1365-
mock_submitter.can_submit.assert_called_once_with(fileinfo)
1366-
mock_submitter.submit_batch.assert_called_once()
1367-
13681339

13691340
class TestDeleteBatch:
1370-
@pytest.fixture(autouse=True)
1371-
def setUp(self):
1341+
def test_create_batches_with_multiple_objects(self):
13721342
self.result_queue = queue.Queue()
13731343
self.delete_batch = DeleteBatch(self.result_queue)
13741344
self.bucket = 'mybucket'
13751345
self.key = 'mykey'
1376-
1377-
def test_create_batches_with_multiple_objects(self):
13781346
fileinfos = []
13791347
num_objects = MAX_BATCH_SIZE + 5
13801348
for i in range(num_objects):

tests/unit/customizations/s3/test_utils.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
from awscli.customizations.s3.utils import (
2727
AppendFilter,
2828
BucketLister,
29-
BucketVersionLister,
3029
NonSeekableStream,
3130
RequestParamsMapper,
3231
S3PathResolver,
@@ -1082,14 +1081,11 @@ def test_list_object_versions(self):
10821081
{'Versions': [versions[1]], 'DeleteMarkers': delete_markers},
10831082
]
10841083

1085-
lister = BucketVersionLister(self.client, self.date_parser)
1084+
lister = BucketLister(self.client, self.date_parser)
10861085
objects = list(lister.list_object_versions(bucket='foo'))
10871086
expected_version_a = versions[0].copy()
1088-
expected_version_a['DeleteMarker'] = False
10891087
expected_version_b = versions[1].copy()
1090-
expected_version_b['DeleteMarker'] = False
10911088
expected_delete_marker_a = delete_markers[0].copy()
1092-
expected_delete_marker_a['DeleteMarker'] = True
10931089

10941090
assert objects == [
10951091
('foo/a', expected_version_a, 'version1'),
@@ -1115,7 +1111,7 @@ def test_list_object_versions_with_extra_args(self):
11151111
'DeleteMarkers': [],
11161112
}
11171113
]
1118-
lister = BucketVersionLister(self.client, self.date_parser)
1114+
lister = BucketLister(self.client, self.date_parser)
11191115
list(
11201116
lister.list_object_versions(
11211117
bucket='mybucket', extra_args={'RequestPayer': 'requester'}

0 commit comments

Comments
 (0)