| OLD | NEW |
| 1 # -*- coding: utf-8 -*- |
| 1 # Copyright 2011 Google Inc. All Rights Reserved. | 2 # Copyright 2011 Google Inc. All Rights Reserved. |
| 2 # | 3 # |
| 3 # Licensed under the Apache License, Version 2.0 (the "License"); | 4 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 # you may not use this file except in compliance with the License. | 5 # you may not use this file except in compliance with the License. |
| 5 # You may obtain a copy of the License at | 6 # You may obtain a copy of the License at |
| 6 # | 7 # |
| 7 # http://www.apache.org/licenses/LICENSE-2.0 | 8 # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 # | 9 # |
| 9 # Unless required by applicable law or agreed to in writing, software | 10 # Unless required by applicable law or agreed to in writing, software |
| 10 # distributed under the License is distributed on an "AS IS" BASIS, | 11 # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 # See the License for the specific language governing permissions and | 13 # See the License for the specific language governing permissions and |
| 13 # limitations under the License. | 14 # limitations under the License. |
| 15 """Implementation of rb command for deleting cloud storage buckets.""" |
| 14 | 16 |
| 15 from boto.exception import GSResponseError | 17 from __future__ import absolute_import |
| 18 |
| 19 from gslib.cloud_api import NotEmptyException |
| 16 from gslib.command import Command | 20 from gslib.command import Command |
| 17 from gslib.command import COMMAND_NAME | 21 from gslib.cs_api_map import ApiSelector |
| 18 from gslib.command import COMMAND_NAME_ALIASES | |
| 19 from gslib.command import FILE_URIS_OK | |
| 20 from gslib.command import MAX_ARGS | |
| 21 from gslib.command import MIN_ARGS | |
| 22 from gslib.command import PROVIDER_URIS_OK | |
| 23 from gslib.command import SUPPORTED_SUB_ARGS | |
| 24 from gslib.command import URIS_START_ARG | |
| 25 from gslib.exception import CommandException | 22 from gslib.exception import CommandException |
| 26 from gslib.help_provider import HELP_NAME | 23 from gslib.storage_url import StorageUrlFromString |
| 27 from gslib.help_provider import HELP_NAME_ALIASES | |
| 28 from gslib.help_provider import HELP_ONE_LINE_SUMMARY | |
| 29 from gslib.help_provider import HELP_TEXT | |
| 30 from gslib.help_provider import HelpType | |
| 31 from gslib.help_provider import HELP_TYPE | |
| 32 from gslib.util import NO_MAX | 24 from gslib.util import NO_MAX |
| 33 | 25 |
| 34 _detailed_help_text = (""" | 26 |
| 27 _DETAILED_HELP_TEXT = (""" |
| 35 <B>SYNOPSIS</B> | 28 <B>SYNOPSIS</B> |
| 36 gsutil rb uri... | 29 gsutil [-f] rb url... |
| 37 | 30 |
| 38 <B>DESCRIPTION</B> | 31 <B>DESCRIPTION</B> |
| 39 The rb command deletes new bucket. Buckets must be empty before you can delete | 32 The rb command deletes new bucket. Buckets must be empty before you can delete |
| 40 them. | 33 them. |
| 41 | 34 |
| 42 Be certain you want to delete a bucket before you do so, as once it is | 35 Be certain you want to delete a bucket before you do so, as once it is |
| 43 deleted the name becomes available and another user may create a bucket with | 36 deleted the name becomes available and another user may create a bucket with |
| 44 that name. (But see also "DOMAIN NAMED BUCKETS" under "gsutil help naming" | 37 that name. (But see also "DOMAIN NAMED BUCKETS" under "gsutil help naming" |
| 45 for help carving out parts of the bucket name space.) | 38 for help carving out parts of the bucket name space.) |
| 39 |
| 40 |
| 41 <B>OPTIONS</B> |
| 42 -f Continues silently (without printing error messages) despite |
| 43 errors when removing buckets. If some buckets couldn't be removed, |
| 44 gsutil's exit status will be non-zero even if this flag is set. |
| 46 """) | 45 """) |
| 47 | 46 |
| 48 | 47 |
| 49 class RbCommand(Command): | 48 class RbCommand(Command): |
| 50 """Implementation of gsutil rb command.""" | 49 """Implementation of gsutil rb command.""" |
| 51 | 50 |
| 52 # Command specification (processed by parent class). | 51 # Command specification. See base class for documentation. |
| 53 command_spec = { | 52 command_spec = Command.CreateCommandSpec( |
| 54 # Name of command. | 53 'rb', |
| 55 COMMAND_NAME : 'rb', | 54 command_name_aliases=[ |
| 56 # List of command name aliases. | 55 'deletebucket', 'removebucket', 'removebuckets', 'rmdir'], |
| 57 COMMAND_NAME_ALIASES : [ | 56 min_args=1, |
| 58 'deletebucket', 'removebucket', 'removebuckets', 'rmdir'], | 57 max_args=NO_MAX, |
| 59 # Min number of args required by this command. | 58 supported_sub_args='f', |
| 60 MIN_ARGS : 1, | 59 file_url_ok=False, |
| 61 # Max number of args required by this command, or NO_MAX. | 60 provider_url_ok=False, |
| 62 MAX_ARGS : NO_MAX, | 61 urls_start_arg=0, |
| 63 # Getopt-style string specifying acceptable sub args. | 62 gs_api_support=[ApiSelector.XML, ApiSelector.JSON], |
| 64 SUPPORTED_SUB_ARGS : '', | 63 gs_default_api=ApiSelector.JSON, |
| 65 # True if file URIs acceptable for this command. | 64 ) |
| 66 FILE_URIS_OK : False, | 65 # Help specification. See help_provider.py for documentation. |
| 67 # True if provider-only URIs acceptable for this command. | 66 help_spec = Command.HelpSpec( |
| 68 PROVIDER_URIS_OK : False, | 67 help_name='rb', |
| 69 # Index in args of first URI arg. | 68 help_name_aliases=[ |
| 70 URIS_START_ARG : 0, | 69 'deletebucket', 'removebucket', 'removebuckets', 'rmdir'], |
| 71 } | 70 help_type='command_help', |
| 72 help_spec = { | 71 help_one_line_summary='Remove buckets', |
| 73 # Name of command or auxiliary help info for which this help applies. | 72 help_text=_DETAILED_HELP_TEXT, |
| 74 HELP_NAME : 'rb', | 73 subcommand_help_text={}, |
| 75 # List of help name aliases. | 74 ) |
| 76 HELP_NAME_ALIASES : | |
| 77 ['deletebucket', 'removebucket', 'removebuckets', 'rmdir'], | |
| 78 # Type of help: | |
| 79 HELP_TYPE : HelpType.COMMAND_HELP, | |
| 80 # One line summary of this help. | |
| 81 HELP_ONE_LINE_SUMMARY : 'Remove buckets', | |
| 82 # The full help text. | |
| 83 HELP_TEXT : _detailed_help_text, | |
| 84 } | |
| 85 | 75 |
| 86 # Command entry point. | |
| 87 def RunCommand(self): | 76 def RunCommand(self): |
| 88 # Expand bucket name wildcards, if any. | 77 """Command entry point for the rb command.""" |
| 78 self.continue_on_error = False |
| 79 if self.sub_opts: |
| 80 for o, unused_a in self.sub_opts: |
| 81 if o == '-f': |
| 82 self.continue_on_error = True |
| 83 |
| 89 did_some_work = False | 84 did_some_work = False |
| 90 for uri_str in self.args: | 85 some_failed = False |
| 91 for uri in self.WildcardIterator(uri_str).IterUris(): | 86 for url_str in self.args: |
| 92 if uri.object_name: | 87 wildcard_url = StorageUrlFromString(url_str) |
| 93 raise CommandException('"rb" command requires a URI with no object ' | 88 if wildcard_url.IsObject(): |
| 94 'name') | 89 raise CommandException('"rb" command requires a provider or ' |
| 95 self.logger.info('Removing %s...', uri) | 90 'bucket URL') |
| 91 # Wrap WildcardIterator call in try/except so we can avoid printing errors |
| 92 # with -f option if a non-existent URL listed, permission denial happens |
| 93 # while listing, etc. |
| 94 try: |
| 95 # Need to materialize iterator results into a list to catch exceptions. |
| 96 # Since this is listing buckets this list shouldn't be too large to fit |
| 97 # in memory at once. |
| 98 blrs = list(self.WildcardIterator(url_str).IterBuckets()) |
| 99 except: # pylint: disable=bare-except |
| 100 some_failed = True |
| 101 if self.continue_on_error: |
| 102 continue |
| 103 else: |
| 104 raise |
| 105 for blr in blrs: |
| 106 url = blr.storage_url |
| 107 self.logger.info('Removing %s...', url) |
| 96 try: | 108 try: |
| 97 uri.delete_bucket(self.headers) | 109 self.gsutil_api.DeleteBucket(url.bucket_name, provider=url.scheme) |
| 98 except GSResponseError as e: | 110 except NotEmptyException as e: |
| 99 if e.code == 'BucketNotEmpty' and uri.get_versioning_config(): | 111 if self.continue_on_error: |
| 112 continue |
| 113 elif 'VersionedBucketNotEmpty' in e.reason: |
| 100 raise CommandException('Bucket is not empty. Note: this is a ' | 114 raise CommandException('Bucket is not empty. Note: this is a ' |
| 101 'versioned bucket, so to delete all objects' | 115 'versioned bucket, so to delete all ' |
| 102 '\nyou need to use:\n\tgsutil rm -ra %s' | 116 'objects\nyou need to use:' |
| 103 % uri) | 117 '\n\tgsutil rm -r %s' % url) |
| 104 else: | 118 else: |
| 105 raise | 119 raise |
| 120 except: # pylint: disable=bare-except |
| 121 if not self.continue_on_error: |
| 122 raise |
| 106 did_some_work = True | 123 did_some_work = True |
| 107 if not did_some_work: | 124 if not did_some_work: |
| 108 raise CommandException('No URIs matched') | 125 raise CommandException('No URLs matched') |
| 109 return 0 | 126 return 1 if some_failed else 0 |
| 110 | 127 |
| OLD | NEW |