#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # '''The sources module of Mouse. This module has one public function, get_items(), which returns a generator for use in Mouse. It can automatically determine the source type if one is not specified. Sources are checked in the order specified by _source_list. If you want to add another source, simply implement a generator and validator function pair, and add them to _source_list.''' import os import tarfile import zipfile import cStringIO as StringIO class _UnknownArchiveError(Exception): '''An exception to communicate we've discovered a type of archive we can't handle.''' def __init__(self, target): self.target = target def __str__(self): return "Unable to read archive '%s'" % self.target class Item(object): '''An item which needs to be matched.''' def __init__(self, name, file): '''NAME is a label for the object. FILE is a file-like object from which the file contents will be grabbed. It does not need to be seekable, and its file pointer may not be preserved.''' self.name = name self.file = file self._content = None def get_content(self): '''Return the contents of this item.''' if not self._content: self._content = self.file.read() return StringIO.StringIO(self._content) def _get_dir_gen(target): '''Return a generator for Items in the filesystem directory given by TARGET''' def dir_gen_func(): for (dirpath, dirnames, filenames) in os.walk(target): # ignore .svn directories, if in a working copy if '.svn' in dirnames: dirnames.remove('.svn') for filename in filenames: name = os.path.join(dirpath, filename) yield Item(name, open(name)) return dir_gen_func def _get_tar_gen(target): '''Return a generator for Items in the tarfile (potentially bzip'd or gzip'd) given by TARGET''' tar = tarfile.open(target, 'r') def tar_gen_func(): for info in tar.getmembers(): if info.isdir(): continue yield Item(info.name, tar.extractfile(info)) return tar_gen_func def _get_zip_gen(target): '''Return a generator for Items in the zipfile given by TARGET''' zip = zipfile.ZipFile(target, 'r') def zip_gen_func(): for info in zip.infolist(): if info.filename[-1] == '/': continue yield Item(info.filename, zip.open(info)) return zip_gen_func _source_list = [ ("dir", os.path.isdir, _get_dir_gen), ("tar", tarfile.is_tarfile, _get_tar_gen), ("zip", zipfile.is_zipfile, _get_zip_gen), ] def get_items(target): '''Using TARGET as the source, return a generator or iterable suitable for use as input to generate_report().''' for name, check_func, get_gen_func in _source_list: if not check_func(target): continue return get_gen_func(target) # if we get to this point, we've no idea what the user gave us, so throw # an appropriate exception raise _UnknownArchiveError(target)