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

Unified Diff: third_party/gsutil/20110627/gslib/wildcard_iterator.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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/gsutil/20110627/gslib/test_wildcard_iterator.py ('k') | third_party/gsutil/20110627/gsutil » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/gsutil/20110627/gslib/wildcard_iterator.py
diff --git a/third_party/gsutil/20110627/gslib/wildcard_iterator.py b/third_party/gsutil/20110627/gslib/wildcard_iterator.py
deleted file mode 100755
index 3b96088b507d11c2adfe2a8f89b9d07e207b4124..0000000000000000000000000000000000000000
--- a/third_party/gsutil/20110627/gslib/wildcard_iterator.py
+++ /dev/null
@@ -1,411 +0,0 @@
-# Copyright 2010 Google Inc.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-
-"""Implementation of wildcarding over StorageUris.
-
-StorageUri is an abstraction that Google introduced in the boto library,
-for representing storage provider-independent bucket and object names with
-a shorthand URI-like syntax (see boto/boto/storage_uri.py) The current
-class provides wildcarding support for StorageUri objects (including both
-bucket and file system objects), allowing one to express collections of
-objects with syntax like the following:
- gs://mybucket/images/*.png
- file:///tmp/???abc???
-
-We provide wildcarding support as part of gsutil rather than as part
-of boto because wildcarding is really part of shell command-like
-functionality.
-
-A comment about wildcard semantics: In a hierarchical file system it's common
-to distinguish recursive from single path component wildcards (e.g., using
-'**' for the former and '*' for the latter). For example,
- /opt/eclipse/*/*.html
-would enumerate HTML files one directory down from /opt/eclipse, while
- /opt/eclipse/**/*.html
-would enumerate HTML files in all subdirectories of /opt/eclipse. We provide
-'**' wildcarding support for file system directories but '*' and '**' behave
-the same for bucket URIs because the bucket namespace is flat (i.e.,
-there's no meaningful distinction between '*' and '**' for buckets).
-Thus, for example, if you were to upload data using the following command:
- % gsutil cp -r /opt/eclipse gs://bucket/eclipse
-it would create a set of objects mirroring the filename hierarchy, and
-the following two commands would yield identical results:
- % gsutil ls gs://bucket/eclipse/*/*.html
- % gsutil ls gs://bucket/eclipse/**/*.html
-
-Note also that if you use file system wildcards it's likely your shell
-interprets the wildcarding before passing the command to gsutil. For example:
- % gsutil cp /opt/eclipse/*/*.html gs://bucket/eclipse
-would likely be expanded by the shell into the following before running gsutil:
- % gsutil cp /opt/eclipse/RUNNING.html gs://bucket/eclipse
-
-Note also that some shells (e.g., bash) don't support '**' wildcarding. If
-you want to use '**' wildcarding with such a shell you can single quote
-each wildcarded string, so it gets passed uninterpreted by the shell to
-gsutil (at which point gsutil will perform the wildcarding expansion):
- % gsutil cp '/opt/eclipse/**/*.html' gs://bucket/eclipse
-"""
-
-import fnmatch
-import glob
-import os
-import re
-import time
-import urllib
-import boto
-from boto.storage_uri import BucketStorageUri
-
-WILDCARD_REGEX = re.compile('[*?\[\]]')
-WILDCARD_OBJECT_ITERATOR = 'wildcard_object_iterator'
-WILDCARD_BUCKET_ITERATOR = 'wildcard_bucket_iterator'
-
-
-# Enum class for specifying what to return from each iteration.
-class ResultType(object):
- KEYS = 'KEYS'
- URIS = 'URIS'
-
-
-class WildcardIterator(object):
- """Base class for wildcarding over StorageUris.
-
- This class implements support for iterating over StorageUris that
- contain wildcards, such as 'gs://bucket/abc*' and 'file://directory/abc*'.
-
- The base class is abstract; you should instantiate using the
- wildcard_iterator() static factory method, which chooses the right
- implementation depending on the StorageUri.
- """
-
- def __repr__(self):
- """Returns string representation of WildcardIterator."""
- return 'WildcardIterator(%s, %s)' % (self.wildcard_uri, self.result_type)
-
-
-class CloudWildcardIterator(WildcardIterator):
- """WildcardIterator subclass for buckets and objects.
-
- Iterates over Keys or URIs matching the StorageUri wildcard. It's more
- efficient to use this method to iterate keys if you want to get metadata
- that's available in the Bucket (for example to get the name and size of
- each object), because that information is available in the bucket GET
- results. If you were to iterate over URIs for such cases and then get
- the name and size info from each resulting StorageUri, it would cause
- an additional object GET request for each of the result URIs.
- """
-
- def __init__(self, wildcard_uri, proj_id_handler, result_type,
- bucket_storage_uri_class=BucketStorageUri,
- headers=None, debug=0):
- """Instantiate an iterator over keys matching given wildcard URI.
-
- Args:
- wildcard_uri: StorageUri that contains the wildcard to iterate.
- proj_id_handler: ProjectIdHandler to use for current command.
- result_type: ResultType object specifying what to iterate.
- bucket_storage_uri_class: BucketStorageUri interface.
- Settable for testing/mocking.
- headers: dictionary containing optional HTTP headers to pass to boto.
- debug: debug level to pass in to boto connection (range 0..3).
-
- Raises:
- WildcardException: for invalid result_type.
- """
- self.wildcard_uri = wildcard_uri
- self.result_type = result_type
- if result_type != ResultType.KEYS and result_type != ResultType.URIS:
- raise WildcardException('Invalid ResultType (%s)' % result_type)
- # Make a copy of the headers so any updates we make during wildcard
- # expansion aren't left in the input params (specifically, so we don't
- # include the x-goog-project-id header needed by a subset of cases, in
- # the data returned to caller, which could then be used in other cases
- # where that header must not be passed).
- self.headers = headers.copy()
- self.proj_id_handler = proj_id_handler
- self.debug = debug
- self.bucket_storage_uri_class = bucket_storage_uri_class
-
- def __NeededResultType(self, obj, uri, headers):
- """Helper function to generate needed ResultType, per constructor param.
-
- Args:
- obj: Key form of object to return, or None if not available.
- uri: StorageUri form of object to return.
- headers: dictionary containing optional HTTP headers to pass to boto.
-
- Returns:
- StorageUri or subclass of boto.s3.key.Key, depending on constructor param.
-
- Raises:
- WildcardException: for bucket-only uri with ResultType.KEYS.
- """
- if self.result_type == ResultType.URIS:
- return uri
- # Else ResultType.KEYS.
- if not obj:
- if not uri.object_name:
- raise WildcardException('Bucket-only URI (%s) with ResultType.KEYS '
- 'iteration request' % uri)
- # This case happens when we do gsutil ls -l on a object name-ful
- # StorageUri with no object-name wildcard. Since the ListCommand
- # implementation only reads bucket info we need to read the object
- # for this case.
- obj = uri.get_key(validate=False, headers=headers)
- # When we retrieve the object this way its last_modified timestamp
- # is formatted in RFC 1123 format, which is different from when we
- # retrieve from the bucket listing (which uses ISO 8601 format), so
- # convert so we consistently return ISO 8601 format.
- tuple_time = (time.strptime(obj.last_modified, '%a, %d %b %Y %H:%M:%S %Z'))
- obj.last_modified = time.strftime('%Y-%m-%dT%H:%M:%S', tuple_time)
- return obj
-
- def __iter__(self):
- """Python iterator that gets called when iterating over cloud wildcard.
-
- Yields:
- StorageUri or Key, per constructor param.
-
- Raises:
- WildcardException: If there were no matches for the given wildcard.
- """
- some_matched = False
- # First handle bucket wildcarding, if any.
- if ContainsWildcard(self.wildcard_uri.bucket_name):
- regex = fnmatch.translate(self.wildcard_uri.bucket_name)
- bucket_uris = []
- prog = re.compile(regex)
- self.proj_id_handler.FillInProjectHeaderIfNeeded(WILDCARD_BUCKET_ITERATOR,
- self.wildcard_uri,
- self.headers)
- for b in self.wildcard_uri.get_all_buckets(headers=self.headers):
- if prog.match(b.name):
- # Use str(b.name) because get_all_buckets() returns Unicode
- # string, which when used to construct x-goog-copy-src metadata
- # requests for object-to-object copies, causes pathname '/' chars
- # to be entity-encoded (bucket%2Fdir instead of bucket/dir),
- # which causes the request to fail.
- uri_str = '%s://%s' % (self.wildcard_uri.scheme,
- urllib.quote_plus(str(b.name)))
- bucket_uris.append(
- boto.storage_uri(
- uri_str, debug=self.debug,
- bucket_storage_uri_class=self.bucket_storage_uri_class))
- else:
- bucket_uris = [self.wildcard_uri.clone_replace_name('')]
-
- # Now iterate over bucket(s), and handle object wildcarding, if any.
- self.proj_id_handler.FillInProjectHeaderIfNeeded(WILDCARD_OBJECT_ITERATOR,
- self.wildcard_uri,
- self.headers)
- for bucket_uri in bucket_uris:
- if not self.wildcard_uri.object_name:
- # Bucket-only URI.
- some_matched = True
- yield self.__NeededResultType(None, bucket_uri, self.headers)
- else:
- # URI contains an object name. If there's no wildcard just yield
- # the needed URI.
- if not ContainsWildcard(self.wildcard_uri.object_name):
- some_matched = True
- uri_to_yield = bucket_uri.clone_replace_name(
- self.wildcard_uri.object_name)
- yield self.__NeededResultType(None, uri_to_yield, self.headers)
- else:
- # Add the input URI's object name part to the bucket we're
- # currently listing. For example if the request was to iterate
- # gs://*/*.txt, bucket_uris will contain a list of all the user's
- # buckets, and for each we'll add *.txt to the end so we iterate
- # the matching files from each bucket in turn.
- uri_to_list = bucket_uri.clone_replace_name(
- self.wildcard_uri.object_name)
- # URI contains an object wildcard.
- for obj in self.__ListObjsInBucket(uri_to_list):
- regex = fnmatch.translate(self.wildcard_uri.object_name)
- prog = re.compile(regex)
- if prog.match(obj.name):
- some_matched = True
- expanded_uri = uri_to_list.clone_replace_name(obj.name)
- yield self.__NeededResultType(obj, expanded_uri, self.headers)
-
- if not some_matched:
- raise WildcardException('No matches for "%s"' % self.wildcard_uri)
-
- def __ListObjsInBucket(self, uri):
- """Helper function to get a list of objects in a bucket.
-
- This function does not provide the complete wildcard match; instead
- it uses the server request prefix (if applicable) to reduce server
- and network load and returns the underlying boto bucket iterator,
- against which remaining wildcard filtering must be applied by the
- caller. For example, for StorageUri('gs://bucket/abc*xyz') this
- method returns the iterator from doing a prefix='abc' bucket GET
- request; and subsequently a regex needs to be applied to subset the
- 'abc'-prefix matches down to the subset matching 'abc*xyz'.
-
- Args:
- uri: StorageUri to list.
-
- Returns:
- An instance of a boto.s3.BucketListResultSet that handles paging, etc.
- """
-
- # Generate a request prefix if the object name part of the
- # wildcard starts with a non-regex string (e.g., that's true for
- # 'gs://bucket/abc*xyz').
- match = WILDCARD_REGEX.search(uri.object_name)
- if match and match.start() > 0:
- # Glob occurs at beginning of object name, so construct a prefix
- # string to send to server.
- prefix = uri.object_name[:match.start()]
- else:
- prefix = None
- return uri.get_bucket(validate=False, headers=self.headers).list(
- prefix=prefix, headers=self.headers)
-
-
-class FileWildcardIterator(WildcardIterator):
- """WildcardIterator subclass for files and directories.
-
- If you use recursive wildcards ('**') only a single such wildcard is
- supported. For example you could use the wildcard '**/*.txt' to list all .txt
- files in any subdirectory of the current directory, but you couldn't use a
- wildcard like '**/abc/**/*.txt' (which would, if supported, let you find .txt
- files in any subdirectory named 'abc').
- """
-
- def __init__(self, wildcard_uri, result_type, headers=None, debug=0):
- """Instantiate an iterator over keys matching given wildcard URI.
-
- Args:
- wildcard_uri: StorageUri that contains the wildcard to iterate.
- result_type: ResultType object specifying what to iterate.
- headers: dictionary containing optional HTTP headers to pass to boto.
- debug: debug level to pass in to boto connection (range 0..3).
-
- Raises:
- WildcardException: for invalid result_type.
- """
- self.wildcard_uri = wildcard_uri
- self.result_type = result_type
- if result_type != ResultType.KEYS and result_type != ResultType.URIS:
- raise WildcardException('Invalid ResultType (%s)' % result_type)
- self.headers = headers
- self.debug = debug
-
- def __iter__(self):
- wildcard = self.wildcard_uri.object_name
- match = re.search('\*\*', wildcard)
- if match:
- # Recursive wildcarding request ('.../**/...').
- # Example input: wildcard = '/tmp/tmp2pQJAX/**/*'
- base_dir = wildcard[:match.start()-1]
- remaining_wildcard = wildcard[match.start()+2:]
- # At this point for the above example base_dir = '/tmp/tmp2pQJAX' and
- # remaining_wildcard = '/*'
- if remaining_wildcard.startswith('*'):
- raise WildcardException('Invalid wildcard with more than 2 consecutive '
- '*s (%s)' % wildcard)
- # If there was no remaining wildcard past the recursive wildcard,
- # treat it as if it were a '*'. For example, file://tmp/** is equivalent
- # to file://tmp/**/*
- if not remaining_wildcard:
- remaining_wildcard = '*'
- # Skip slash(es).
- remaining_wildcard = remaining_wildcard.lstrip('/')
- filepaths = []
- for dirpath, unused_dirnames, filenames in os.walk(base_dir):
- filepaths.extend(
- os.path.join(dirpath, f) for f in fnmatch.filter(filenames,
- remaining_wildcard)
- )
- else:
- # Not a recursive wildcarding request.
- filepaths = glob.glob(wildcard)
- for filepath in filepaths:
- expanded_uri = self.wildcard_uri.clone_replace_name(filepath)
- yield expanded_uri
-
-
-class WildcardException(StandardError):
- """Exception thrown for invalid wildcard URIs."""
-
- def __init__(self, reason):
- StandardError.__init__(self)
- self.reason = reason
-
- def __repr__(self):
- return 'WildcardException: %s' % self.reason
-
- def __str__(self):
- return 'WildcardException: %s' % self.reason
-
-
-def wildcard_iterator(uri_or_str, proj_id_handler,
- result_type=ResultType.URIS,
- bucket_storage_uri_class=BucketStorageUri,
- headers=None, debug=0):
- """Instantiate a WildCardIterator for the given StorageUri.
-
- Args:
- uri_or_str: StorageUri or URI string naming wildcard objects to iterate.
- proj_id_handler: ProjectIdHandler to use for current command.
- result_type: ResultType object specifying what to iterate.
- bucket_storage_uri_class: BucketStorageUri interface.
- Settable for testing/mocking.
- headers: dictionary containing optional HTTP headers to pass to boto.
- debug: debug level to pass in to boto connection (range 0..3).
-
- Returns:
- A WildcardIterator that handles the requested iteration.
-
- Raises:
- WildcardException: if invalid result_type.
- """
-
- if isinstance(uri_or_str, basestring):
- # Disable enforce_bucket_naming, to allow bucket names containing
- # wildcard chars.
- uri = boto.storage_uri(
- uri_or_str, debug=debug, validate=False,
- bucket_storage_uri_class=bucket_storage_uri_class)
- else:
- uri = uri_or_str
-
- if uri.is_cloud_uri():
- return CloudWildcardIterator(uri, proj_id_handler, result_type,
- bucket_storage_uri_class, headers, debug)
- elif uri.is_file_uri():
- return FileWildcardIterator(uri, result_type, headers=headers, debug=debug)
- else:
- raise WildcardException('Unexpected type of StorageUri (%s)' % uri)
-
-
-def ContainsWildcard(uri_str):
- """Checks whether given URI contains a wildcard.
-
- Args:
- uri_str: string to check.
-
- Returns:
- True or False.
- """
-
- return WILDCARD_REGEX.search(uri_str) is not None
« no previous file with comments | « third_party/gsutil/20110627/gslib/test_wildcard_iterator.py ('k') | third_party/gsutil/20110627/gsutil » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698