Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(320)

Side by Side Diff: third_party/gsutil/gslib/commands/ls.py

Issue 10199002: Upgrade gsutil to 3.4 (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed comments Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/gsutil/gslib/commands/help.py ('k') | third_party/gsutil/gslib/commands/mb.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2011 Google Inc.
2 #
3 # 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 obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 from gslib.bucket_listing_ref import BucketListingRef
16 from gslib.command import Command
17 from gslib.command import COMMAND_NAME
18 from gslib.command import COMMAND_NAME_ALIASES
19 from gslib.command import CONFIG_REQUIRED
20 from gslib.command import FILE_URIS_OK
21 from gslib.command import MAX_ARGS
22 from gslib.command import MIN_ARGS
23 from gslib.command import PROVIDER_URIS_OK
24 from gslib.command import SUPPORTED_SUB_ARGS
25 from gslib.command import URIS_START_ARG
26 from gslib.help_provider import HELP_NAME
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 ListingStyle
33 from gslib.util import MakeHumanReadable
34 from gslib.util import NO_MAX
35 from gslib.wildcard_iterator import ContainsWildcard
36
37 _detailed_help_text = ("""
38 <B>SYNOPSIS</B>
39 gsutil ls [-b] [-l] [-L] [-R] [-p proj_id] uri...
40
41
42 <B>LISTING PROVIDERS, BUCKETS, SUBDIRECTORIES, AND OBJECTS</B>
43 If you run gsutil ls without URIs, it lists all of the Google Cloud Storage
44 buckets under your default project ID:
45
46 gsutil ls
47
48 (For details about projects, see "gsutil help projects" and also the -p
49 option in the OPTIONS section below.)
50
51 If you specify one or more provider URIs, gsutil ls will list buckets at
52 each listed provider:
53
54 gsutil ls gs://
55
56 If you specify bucket URIs, gsutil ls will list objects at the top level of
57 each bucket, along with the names of each subdirectory. For example:
58
59 gsutil ls gs://bucket
60
61 might produce output like:
62
63 gs://bucket/obj1.htm
64 gs://bucket/obj2.htm
65 gs://bucket/images1/
66 gs://bucket/images2/
67
68 The "/" at the end of the last 2 URIs tells you they are subdirectories,
69 which you can list using:
70
71 gsutil ls gs://bucket/images*
72
73 If you specify object URIs, gsutil ls will list the specified objects. For
74 example:
75
76 gsutil ls gs://bucket/*.txt
77
78 will list all files whose name matches the above wildcard at the top level
79 of the bucket.
80
81 See "gsutil help wildcards" for more details on working with wildcards.
82
83
84 <B>DIRECTORY BY DIRECTORY, FLAT, and RECURSIVE LISTINGS</B>
85 Listing a bucket or subdirectory (as illustrated near the end of the previous
86 section) only shows the objects and names of subdirectories it contains. You
87 can list all objects in a bucket by using the -R option. For example:
88
89 gsutil ls -R gs://bucket
90
91 will list the top-level objects and buckets, then the objects and
92 buckets under gs://bucket/images1, then those under gs://bucket/images2, etc.
93
94 If you want to see all objects in the bucket in one "flat" listing use the
95 recursive ("**") wildcard, like:
96
97 gsutil ls -R gs://bucket/**
98
99 or, for a flat listing of a subdirectory:
100
101 gsutil ls -R gs://bucket/dir/**
102
103
104 <B>LISTING OBJECT DETAILS</B>
105 If you specify the -l option, gsutil will output additional information
106 about each matching provider, bucket, subdirectory, or object. For example,
107
108 gsutil ls -l gs://bucket/*.txt
109
110 will print the object size, creation time stamp, and name of each matching
111 object, along with the total count and sum of sizes of all matching objects:
112
113 2276224 2012-03-02T19:25:17 gs://bucket/obj1
114 3914624 2012-03-02T19:30:27 gs://bucket/obj2
115 TOTAL: 2 objects, 6190848 bytes (5.9 MB)
116
117 Note that the total listed in parentheses above is in mebibytes (or gibibytes,
118 tebibytes, etc.), which corresponds to the unit of billing measurement for
119 Google Cloud Storage.
120
121 You can get a listing of all the objects in the top-level bucket directory
122 (along with the total count and sum of sizes) using a command like:
123
124 gsutil ls -l gs://bucket
125
126 To print additional detail about objects and buckets use the gsutil ls -L
127 option. For example:
128
129 gsutil ls -L gs://bucket/obj1
130
131 will print something like:
132
133 gs://bucket/obj1:
134 Object size: 2276224
135 Last mod: Fri, 02 Mar 2012 19:25:17 GMT
136 Cache control: private, max-age=0
137 MIME type: application/x-executable
138 Etag: 5ca6796417570a586723b7344afffc81
139 ACL: <Owner:00b4903a97163d99003117abe64d292561d2b4074fc90ce5c 0e35ac45f66ad70, <<UserById: 00b4903a97163d99003117abe64d292561d2b4074fc90ce5c0e 35ac45f66ad70>: u'FULL_CONTROL'>>
140 TOTAL: 1 objects, 2276224 bytes (2.17 MB)
141
142 Note that the -L option is slower and more costly to use than the -l option,
143 because it makes a bucket listing request followed by a HEAD request for
144 each individual object (rather than just parsing the information it needs
145 out of a single bucket listing, the way the -l option does).
146
147 See also "gsutil help getacl" for getting a more readable version of the ACL.
148
149
150 <B>LISTING BUCKET DETAILS</B>
151 If you want to see information about the bucket itself, use the -b
152 option. For example:
153
154 gsutil ls -L -b gs://bucket
155
156 will print something like:
157
158 gs://bucket/ :
159 24 objects, 29.83 KB
160 LocationConstraint: US
161 ACL: <Owner:00b4903a9740e42c29800f53bd5a9a62a2f96eb3f64a4313a115df3f 3a776bf7, <<GroupById: 00b4903a9740e42c29800f53bd5a9a62a2f96eb3f64a4313a115df3f3 a776bf7>: u'FULL_CONTROL'>>
162 Default ACL: <>
163 TOTAL: 24 objects, 30544 bytes (29.83 KB)
164
165
166 <B>OPTIONS</B>
167 -l Prints long listing (owner, length).
168
169 -L Prints even more detail than -L. This is a separate option because
170 it makes additional service requests (so, takes longer and adds
171 requests costs).
172
173 -b Prints info about the bucket when used with a bucket URI.
174
175 -p proj_id Specifies the project ID to use for listing buckets.
176
177 -R, -r Requests a recursive listing.
178 """)
179
180
181 class LsCommand(Command):
182 """Implementation of gsutil ls command."""
183
184 # Command specification (processed by parent class).
185 command_spec = {
186 # Name of command.
187 COMMAND_NAME : 'ls',
188 # List of command name aliases.
189 COMMAND_NAME_ALIASES : ['dir', 'list'],
190 # Min number of args required by this command.
191 MIN_ARGS : 0,
192 # Max number of args required by this command, or NO_MAX.
193 MAX_ARGS : NO_MAX,
194 # Getopt-style string specifying acceptable sub args.
195 SUPPORTED_SUB_ARGS : 'blLp:rR',
196 # True if file URIs acceptable for this command.
197 FILE_URIS_OK : False,
198 # True if provider-only URIs acceptable for this command.
199 PROVIDER_URIS_OK : True,
200 # Index in args of first URI arg.
201 URIS_START_ARG : 0,
202 # True if must configure gsutil before running command.
203 CONFIG_REQUIRED : True,
204 }
205 help_spec = {
206 # Name of command or auxiliary help info for which this help applies.
207 HELP_NAME : 'ls',
208 # List of help name aliases.
209 HELP_NAME_ALIASES : ['dir', 'list'],
210 # Type of help:
211 HELP_TYPE : HelpType.COMMAND_HELP,
212 # One line summary of this help.
213 HELP_ONE_LINE_SUMMARY : 'List providers, buckets, or objects',
214 # The full help text.
215 HELP_TEXT : _detailed_help_text,
216 }
217
218 def _PrintBucketInfo(self, bucket_uri, listing_style):
219 """Print listing info for given bucket.
220
221 Args:
222 bucket_uri: StorageUri being listed.
223 listing_style: ListingStyle enum describing type of output desired.
224
225 Returns:
226 Tuple (total objects, total bytes) in the bucket.
227 """
228 bucket_objs = 0
229 bucket_bytes = 0
230 if listing_style == ListingStyle.SHORT:
231 print bucket_uri
232 else:
233 for obj in self.exp_handler.WildcardIterator(
234 bucket_uri.clone_replace_name('**')).IterKeys():
235 bucket_objs += 1
236 bucket_bytes += obj.size
237 if listing_style == ListingStyle.LONG:
238 print '%s : %s objects, %s' % (
239 bucket_uri, bucket_objs, MakeHumanReadable(bucket_bytes))
240 else: # listing_style == ListingStyle.LONG_LONG:
241 location_constraint = bucket_uri.get_location(validate=False,
242 headers=self.headers)
243 location_output = ''
244 if location_constraint:
245 location_output = '\n\tLocationConstraint: %s' % location_constraint
246 self.proj_id_handler.FillInProjectHeaderIfNeeded(
247 'get_acl', bucket_uri, self.headers)
248 print '%s :\n\t%d objects, %s%s\n\tACL: %s\n\tDefault ACL: %s' % (
249 bucket_uri, bucket_objs, MakeHumanReadable(bucket_bytes),
250 location_output, bucket_uri.get_acl(False, self.headers),
251 bucket_uri.get_def_acl(False, self.headers))
252 return (bucket_objs, bucket_bytes)
253
254 def _UriStrForObj(self, uri, obj):
255 """Constructs a URI string for the given object.
256
257 For example if we were iterating gs://*, obj could be an object in one
258 of the user's buckets enumerated by the ls command.
259
260 Args:
261 uri: base StorageUri being iterated.
262 obj: object (Key) being listed.
263
264 Returns:
265 URI string.
266 """
267 return '%s://%s/%s' % (uri.scheme, obj.bucket.name, obj.name)
268
269 def _PrintInfoAboutBucketListingRef(self, bucket_listing_ref, listing_style):
270 """Print listing info for given bucket_listing_ref.
271
272 Args:
273 bucket_listing_ref: BucketListing being listed.
274 listing_style: ListingStyle enum describing type of output desired.
275
276 Returns:
277 Tuple (number of objects,
278 object length, if listing_style is one of the long listing formats)
279
280 Raises:
281 Exception: if calling bug encountered.
282 """
283 uri = bucket_listing_ref.GetUri()
284 obj = bucket_listing_ref.GetKey()
285 if listing_style == ListingStyle.SHORT:
286 print self._UriStrForObj(uri, obj).encode('utf-8')
287 return (0, 0)
288 elif listing_style == ListingStyle.LONG:
289 # Exclude timestamp fractional secs (example: 2010-08-23T12:46:54.187Z).
290 timestamp = obj.last_modified[:19].decode('utf8').encode('ascii')
291 print '%10s %s %s' % (obj.size, timestamp,
292 self._UriStrForObj(uri, obj).encode('utf-8'))
293 return (1, obj.size)
294 elif listing_style == ListingStyle.LONG_LONG:
295 uri_str = self._UriStrForObj(uri, obj)
296 print '%s:' % uri_str.encode('utf-8')
297 obj = self.suri_builder.StorageUri(uri_str).get_key(False)
298 print '\tObject size:\t%s' % obj.size
299 print '\tLast mod:\t%s' % obj.last_modified
300 if obj.cache_control:
301 print '\tCache control:\t%s' % obj.cache_control
302 print '\tMIME type:\t%s' % obj.content_type
303 if obj.content_disposition:
304 print '\tContent-Disposition:\t%s' % obj.content_disposition
305 if obj.content_encoding:
306 print '\tContent-Encoding:\t%s' % obj.content_encoding
307 if obj.metadata:
308 for name in obj.metadata:
309 print '\tMetadata:\t%s = %s' % (name, obj.metadata[name])
310 print '\tEtag:\t%s' % obj.etag.strip('"\'')
311 print '\tACL:\t%s' % (
312 self.suri_builder.StorageUri(uri_str).get_acl(False, self.headers))
313 return (1, obj.size)
314 else:
315 raise Exception('Unexpected ListingStyle(%s)' % listing_style)
316
317 def _BuildBlrExpansionForUriOnlyBlr(self, blr):
318 """
319 Builds BucketListingRef expansion from BucketListingRef that contains only a
320 URI (i.e., didn't come from a bucket listing). This case happens for BLR's
321 instantiated from a user-provided URI.
322
323 Args:
324 blr: BucketListingRef to expand
325
326 Returns:
327 List of BucketListingRef to which it expands.
328 """
329 # Do a delimited wildcard expansion so we get any matches along with
330 # whether they are keys or prefixes. That way if bucket contains a key
331 # 'abcd' and another key 'abce/x.txt' the expansion will return two BLRs,
332 # the first with HasKey()=True and the second with HasPrefix()=True.
333 rstripped_blr = blr.GetRStrippedUriString()
334 if ContainsWildcard(rstripped_blr):
335 return list(self.exp_handler.WildcardIterator(rstripped_blr))
336 # Build a wildcard to expand so CloudWildcardIterator will not just treat it
337 # as a key and yield the result without doing a bucket listing.
338 blr_expansion = list(
339 self.exp_handler.WildcardIterator(rstripped_blr + '*'))
340 # Find the originally specified blr in the expanded list (if present). Don't
341 # just use the expanded list, since it would also include objects whose name
342 # prefix matches the blr name (because of the wildcard match we did above).
343 # Note that there can be multiple matches, for the case where there's
344 # both an object and a subdirectory with the same name.
345 exp_result = []
346 for cur_blr in blr_expansion:
347 if cur_blr.GetRStrippedUriString() == rstripped_blr:
348 exp_result.append(cur_blr)
349 return exp_result
350
351 def _ExpandUriAndPrintInfo(self, uri, listing_style, should_recurse=False):
352 """
353 Expands wildcards and directories/buckets for uri as needed, and
354 calls _PrintInfoAboutBucketListingRef() on each.
355
356 Args:
357 uri: StorageUri being listed.
358 listing_style: ListingStyle enum describing type of output desired.
359 should_recurse: bool indicator of whether to expand recursively.
360
361 Returns:
362 Tuple (number of matching objects, number of bytes across these objects).
363 """
364 # We do a two-level loop, with the outer loop iterating level-by-level from
365 # blrs_to_expand, and the inner loop iterating the matches at the current
366 # level, printing them, and adding any new subdirs that need expanding to
367 # blrs_to_expand (to be picked up in the next outer loop iteration).
368 blrs_to_expand = [BucketListingRef(uri)]
369 num_objs = 0
370 num_bytes = 0
371 expanding_top_level = True
372 printed_one = False
373 num_expanded_blrs = 0
374 while len(blrs_to_expand):
375 if printed_one:
376 print
377 blr = blrs_to_expand.pop(0)
378 if blr.HasKey():
379 blr_expansion = [blr]
380 elif blr.HasPrefix():
381 # Bucket subdir from a previous iteration. Print "header" line only if
382 # we're listing more than one subdir (or if it's a recursive listing),
383 # to be consistent with the way UNIX ls works.
384 if num_expanded_blrs > 1 or should_recurse:
385 print '%s:' % blr.GetUriString().encode('utf-8')
386 printed_one = True
387 blr_expansion = list(self.exp_handler.WildcardIterator(
388 '%s/*' % blr.GetRStrippedUriString()))
389 elif blr.NamesBucket():
390 blr_expansion = list(self.exp_handler.WildcardIterator(
391 '%s*' % blr.GetUriString()))
392 else:
393 # This BLR didn't come from a bucket listing. This case happens for
394 # BLR's instantiated from a user-provided URI.
395 blr_expansion = self._BuildBlrExpansionForUriOnlyBlr(blr)
396 num_expanded_blrs += len(blr_expansion)
397 for cur_blr in blr_expansion:
398 if cur_blr.HasKey():
399 # Object listing.
400 (no, nb) = self._PrintInfoAboutBucketListingRef(
401 cur_blr, listing_style)
402 num_objs += no
403 num_bytes += nb
404 printed_one = True
405 else:
406 # Subdir listing. If we're at the top level of a bucket subdir
407 # listing don't print the list here (corresponding to how UNIX ls
408 # dir just prints its contents, not the name followed by its
409 # contents).
410 if (expanding_top_level and not uri.names_bucket()) or should_recurse:
411 if cur_blr.GetUriString().endswith('//'):
412 # Expand gs://bucket// into gs://bucket//* so we don't infinite
413 # loop. This case happens when user has uploaded an object whose
414 # name begins with a /.
415 cur_blr = BucketListingRef(self.suri_builder.StorageUri(
416 '%s*' % cur_blr.GetUriString()), None, None, cur_blr.headers)
417 blrs_to_expand.append(cur_blr)
418 # Don't include the subdir name in the output if we're doing a
419 # recursive listing, as it will be printed as 'subdir:' when we get
420 # to the prefix expansion, the next iteration of the main loop.
421 else:
422 if listing_style == ListingStyle.LONG:
423 print '%-33s%s' % ('', cur_blr.GetUriString().encode('utf-8'))
424 else:
425 print cur_blr.GetUriString().encode('utf-8')
426 expanding_top_level = False
427 return (num_objs, num_bytes)
428
429 # Command entry point.
430 def RunCommand(self):
431 listing_style = ListingStyle.SHORT
432 get_bucket_info = False
433 self.recursion_requested = False
434 if self.sub_opts:
435 for o, a in self.sub_opts:
436 if o == '-b':
437 get_bucket_info = True
438 elif o == '-l':
439 listing_style = ListingStyle.LONG
440 elif o == '-L':
441 listing_style = ListingStyle.LONG_LONG
442 elif o == '-p':
443 self.proj_id_handler.SetProjectId(a)
444 elif o == '-r' or o == '-R':
445 self.recursion_requested = True
446
447 if not self.args:
448 # default to listing all gs buckets
449 self.args = ['gs://']
450
451 total_objs = 0
452 total_bytes = 0
453 for uri_str in self.args:
454 uri = self.suri_builder.StorageUri(uri_str)
455 self.proj_id_handler.FillInProjectHeaderIfNeeded('ls', uri, self.headers)
456
457 if uri.names_provider():
458 # Provider URI: use bucket wildcard to list buckets.
459 for uri in self.exp_handler.WildcardIterator(
460 '%s://*' % uri.scheme).IterUris():
461 (bucket_objs, bucket_bytes) = self._PrintBucketInfo(uri,
462 listing_style)
463 total_bytes += bucket_bytes
464 total_objs += bucket_objs
465 elif uri.names_bucket():
466 # Bucket URI -> list the object(s) in that bucket.
467 if get_bucket_info:
468 # ls -b bucket listing request: List info about bucket(s).
469 for uri in self.exp_handler.WildcardIterator(uri).IterUris():
470 (bucket_objs, bucket_bytes) = self._PrintBucketInfo(uri,
471 listing_style)
472 total_bytes += bucket_bytes
473 total_objs += bucket_objs
474 else:
475 # Not -b request: List objects in the bucket(s).
476 (no, nb) = self._ExpandUriAndPrintInfo(uri, listing_style,
477 should_recurse=self.recursion_requested)
478 total_objs += no
479 total_bytes += nb
480 else:
481 # URI names an object or object subdir -> list matching object(s) /
482 # subdirs.
483 (exp_objs, exp_bytes) = self._ExpandUriAndPrintInfo(uri, listing_style,
484 should_recurse=self.recursion_requested)
485 total_bytes += exp_bytes
486 total_objs += exp_objs
487
488 if total_objs and listing_style != ListingStyle.SHORT:
489 print ('TOTAL: %d objects, %d bytes (%s)' %
490 (total_objs, total_bytes, MakeHumanReadable(float(total_bytes))))
491
492 # test specification, see definition of test_steps in base class for
493 # details on how to populate these fields
494 test_steps = [
495 # (test name, cmd line, ret code, (result_file, expect_file))
496 ('gen bucket expect', 'echo gs://$B0/ >$F9', 0, None),
497 ('gen obj expect', 'echo gs://$B1/$O0 >$F8', 0, None),
498 ('simple ls', 'gsutil ls', 0, None),
499 ('list empty bucket', 'gsutil ls gs://$B0', 0, None),
500 ('list empty bucket w/ -b', 'gsutil ls -b gs://$B0 >$F7', 0,
501 ('$F7', '$F9')),
502 ('list bucket contents', 'gsutil ls gs://$B1 >$F7', 0, ('$F7', '$F8')),
503 ('list object', 'gsutil ls gs://$B1/$O0 >$F7', 0, ('$F7', '$F8')),
504 ]
OLDNEW
« no previous file with comments | « third_party/gsutil/gslib/commands/help.py ('k') | third_party/gsutil/gslib/commands/mb.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698