1 # -*- coding: utf-8 -*-
2 # Copyright 2013 Google Inc. All Rights Reserved.
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
8 # http://www.apache.org/licenses/LICENSE-2.0
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 stat command for cloud storage providers."""
17 from __future__
import absolute_import
21 from gslib
.bucket_listing_ref
import BucketListingObject
22 from gslib
.cloud_api
import AccessDeniedException
23 from gslib
.cloud_api
import NotFoundException
24 from gslib
.command
import Command
25 from gslib
.command_argument
import CommandArgument
26 from gslib
.cs_api_map
import ApiSelector
27 from gslib
.exception
import CommandException
28 from gslib
.exception
import InvalidUrlError
29 from gslib
.storage_url
import ContainsWildcard
30 from gslib
.storage_url
import StorageUrlFromString
31 from gslib
.util
import NO_MAX
32 from gslib
.util
import PrintFullInfoAboutObject
39 _DETAILED_HELP_TEXT
= ("""
45 The stat command will output details about the specified object URLs.
46 It is similar to running:
48 gsutil ls -L gs://some-bucket/some-object
50 but is more efficient because it avoids performing bucket listings and gets
51 the minimum necessary amount of object metadata. Moreover, because it avoids
52 performing bucket listings (which are eventually consistent) the gsutil stat
53 command provides a strongly consistent way to check for the existence (and
54 read the metadata) of an object.
56 The gsutil stat command will, however, perform bucket listings if you specify
59 If run with the gsutil -q option nothing will be printed, e.g.:
61 gsutil -q stat gs://some-bucket/some-object
63 This can be useful for writing scripts, because the exit status will be 0 for
64 an existing object and 1 for a non-existent object.
66 Note: Unlike the gsutil ls command, the stat command does not support
67 operations on sub-directories. For example, if you run the command:
69 gsutil -q stat gs://some-bucket/some-subdir/
71 gsutil will look for information about an object called "some-subdir/" (with a
72 trailing slash) inside the bucket "some-bucket", as opposed to operating on
73 objects nested under gs://some-bucket/some-subdir/. Unless you actually have
74 an object with that name, the operation will fail. However, you can use the
75 stat command on objects within subdirectories. For example, this command will
78 gsutil -q stat gs://some-bucket/some-subdir/file.txt
82 # TODO: Add ability to stat buckets.
83 class StatCommand(Command
):
84 """Implementation of gsutil stat command."""
86 # Command specification. See base class for documentation.
87 command_spec
= Command
.CreateCommandSpec(
89 command_name_aliases
=[],
90 usage_synopsis
=_SYNOPSIS
,
93 supported_sub_args
='',
95 provider_url_ok
=False,
97 gs_api_support
=[ApiSelector
.XML
, ApiSelector
.JSON
],
98 gs_default_api
=ApiSelector
.JSON
,
100 CommandArgument
.MakeZeroOrMoreCloudURLsArgument()
103 # Help specification. See help_provider.py for documentation.
104 help_spec
= Command
.HelpSpec(
106 help_name_aliases
=[],
107 help_type
='command_help',
108 help_one_line_summary
='Display object status',
109 help_text
=_DETAILED_HELP_TEXT
,
110 subcommand_help_text
={},
113 def RunCommand(self
):
114 """Command entry point for stat command."""
115 # List of fields we'll print for stat objects.
116 stat_fields
= ['updated', 'cacheControl', 'contentDisposition',
117 'contentEncoding', 'contentLanguage', 'size', 'contentType',
118 'componentCount', 'metadata', 'crc32c', 'md5Hash', 'etag',
119 'generation', 'metageneration']
120 found_nonmatching_arg
= False
121 for url_str
in self
.args
:
123 url
= StorageUrlFromString(url_str
)
124 if not url
.IsObject():
125 raise CommandException('The stat command only works with object URLs')
127 if ContainsWildcard(url_str
):
128 blr_iter
= self
.WildcardIterator(url_str
).IterObjects(
129 bucket_listing_fields
=stat_fields
)
131 single_obj
= self
.gsutil_api
.GetObjectMetadata(
132 url
.bucket_name
, url
.object_name
, generation
=url
.generation
,
133 provider
=url
.scheme
, fields
=stat_fields
)
134 blr_iter
= [BucketListingObject(url
, root_object
=single_obj
)]
138 if logging
.getLogger().isEnabledFor(logging
.INFO
):
139 PrintFullInfoAboutObject(blr
, incl_acl
=False)
140 except AccessDeniedException
:
141 logging
.info('You aren\'t authorized to read %s - skipping', url_str
)
142 except InvalidUrlError
:
144 except NotFoundException
:
147 if logging
.getLogger().isEnabledFor(logging
.INFO
):
148 logging
.info('No URLs matched %s', url_str
)
149 found_nonmatching_arg
= True
150 if found_nonmatching_arg
: