Home | History | Annotate | Download | only in commands
      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 
     17 from __future__ import absolute_import
     18 
     19 from gslib.command import Command
     20 from gslib.command_argument import CommandArgument
     21 from gslib.commands.cp import CP_SUB_ARGS
     22 from gslib.cs_api_map import ApiSelector
     23 from gslib.exception import CommandException
     24 from gslib.storage_url import StorageUrlFromString
     25 from 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 
     91 class 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