1# -*- coding: utf-8 -*- 2# Copyright 2011 Google Inc. All Rights Reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15"""Implementation of Unix-like mv command for cloud storage providers.""" 16 17from __future__ import absolute_import 18 19from gslib.command import Command 20from gslib.command_argument import CommandArgument 21from gslib.commands.cp import CP_SUB_ARGS 22from gslib.cs_api_map import ApiSelector 23from gslib.exception import CommandException 24from gslib.storage_url import StorageUrlFromString 25from gslib.util import NO_MAX 26 27 28_SYNOPSIS = """ 29 gsutil mv [-p] src_url dst_url 30 gsutil mv [-p] src_url... dst_url 31 gsutil mv [-p] -I dst_url 32""" 33 34_DETAILED_HELP_TEXT = (""" 35<B>SYNOPSIS</B> 36""" + _SYNOPSIS + """ 37 38 39<B>DESCRIPTION</B> 40 The gsutil mv command allows you to move data between your local file 41 system and the cloud, move data within the cloud, and move data between 42 cloud storage providers. For example, to move all objects from a 43 bucket to a local directory you could use: 44 45 gsutil mv gs://my_bucket dir 46 47 Similarly, to move all objects from a local directory to a bucket you could 48 use: 49 50 gsutil mv ./dir gs://my_bucket 51 52 53<B>RENAMING BUCKET SUBDIRECTORIES</B> 54 You can use the gsutil mv command to rename subdirectories. For example, 55 the command: 56 57 gsutil mv gs://my_bucket/olddir gs://my_bucket/newdir 58 59 would rename all objects and subdirectories under gs://my_bucket/olddir to be 60 under gs://my_bucket/newdir, otherwise preserving the subdirectory structure. 61 62 If you do a rename as specified above and you want to preserve ACLs, you 63 should use the -p option (see OPTIONS). 64 65 Note that when using mv to rename bucket subdirectories you cannot specify 66 the source URL using wildcards. You need to spell out the complete name: 67 68 gsutil mv gs://my_bucket/olddir gs://my_bucket/newdir 69 70 If you have a large number of files to move you might want to use the 71 gsutil -m option, to perform a multi-threaded/multi-processing move: 72 73 gsutil -m mv gs://my_bucket/olddir gs://my_bucket/newdir 74 75 76<B>NON-ATOMIC OPERATION</B> 77 Unlike the case with many file systems, the gsutil mv command does not 78 perform a single atomic operation. Rather, it performs a copy from source 79 to destination followed by removing the source for each object. 80 81 82<B>OPTIONS</B> 83 All options that are available for the gsutil cp command are also available 84 for the gsutil mv command (except for the -R flag, which is implied by the 85 gsutil mv command). Please see the OPTIONS sections of "gsutil help cp" 86 for more information. 87 88""") 89 90 91class MvCommand(Command): 92 """Implementation of gsutil mv command. 93 94 Note that there is no atomic rename operation - this command is simply 95 a shorthand for 'cp' followed by 'rm'. 96 """ 97 98 # Command specification. See base class for documentation. 99 command_spec = Command.CreateCommandSpec( 100 'mv', 101 command_name_aliases=['move', 'ren', 'rename'], 102 usage_synopsis=_SYNOPSIS, 103 min_args=1, 104 max_args=NO_MAX, 105 # Flags for mv are passed through to cp. 106 supported_sub_args=CP_SUB_ARGS, 107 file_url_ok=True, 108 provider_url_ok=False, 109 urls_start_arg=0, 110 gs_api_support=[ApiSelector.XML, ApiSelector.JSON], 111 gs_default_api=ApiSelector.JSON, 112 argparse_arguments=[ 113 CommandArgument.MakeZeroOrMoreCloudOrFileURLsArgument() 114 ] 115 ) 116 # Help specification. See help_provider.py for documentation. 117 help_spec = Command.HelpSpec( 118 help_name='mv', 119 help_name_aliases=['move', 'rename'], 120 help_type='command_help', 121 help_one_line_summary='Move/rename objects and/or subdirectories', 122 help_text=_DETAILED_HELP_TEXT, 123 subcommand_help_text={}, 124 ) 125 126 def RunCommand(self): 127 """Command entry point for the mv command.""" 128 # Check each source arg up, refusing to delete a bucket src URL (force users 129 # to explicitly do that as a separate operation). 130 for arg_to_check in self.args[0:-1]: 131 url = StorageUrlFromString(arg_to_check) 132 if url.IsCloudUrl() and (url.IsBucket() or url.IsProvider()): 133 raise CommandException('You cannot move a source bucket using the mv ' 134 'command. If you meant to move\nall objects in ' 135 'the bucket, you can use a command like:\n' 136 '\tgsutil mv %s/* %s' % 137 (arg_to_check, self.args[-1])) 138 139 # Insert command-line opts in front of args so they'll be picked up by cp 140 # and rm commands (e.g., for -p option). Use undocumented (internal 141 # use-only) cp -M option, which causes each original object to be deleted 142 # after successfully copying to its destination, and also causes naming 143 # behavior consistent with Unix mv naming behavior (see comments in 144 # ConstructDstUrl). 145 unparsed_args = ['-M'] 146 if self.recursion_requested: 147 unparsed_args.append('-R') 148 unparsed_args.extend(self.unparsed_args) 149 self.command_runner.RunNamedCommand('cp', unparsed_args, self.headers, 150 self.debug, self.parallel_operations) 151 152 return 0 153