| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | """distutils.filelist
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Provides the FileList class, used for poking about the filesystem | 
					
						
							|  |  |  | and building lists of files. | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # created 2000/07/17, Rene Liebscher (as template.py) | 
					
						
							|  |  |  | # most parts taken from commands/sdist.py | 
					
						
							|  |  |  | # renamed 2000/07/29 (to filelist.py) and officially added to | 
					
						
							| 
									
										
										
										
											2001-12-06 20:51:35 +00:00
										 |  |  | #  the Distutils source, Greg Ward | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | __revision__ = "$Id$" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import sys, os, string, re | 
					
						
							|  |  |  | import fnmatch | 
					
						
							|  |  |  | from types import * | 
					
						
							|  |  |  | from glob import glob | 
					
						
							|  |  |  | from distutils.util import convert_path | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  | from distutils.errors import DistutilsTemplateError, DistutilsInternalError | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class FileList: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  |     """A list of files built by on exploring the filesystem and filtered by
 | 
					
						
							|  |  |  |     applying various patterns to what we find there. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Instance attributes: | 
					
						
							|  |  |  |       dir | 
					
						
							|  |  |  |         directory from which files will be taken -- only used if | 
					
						
							|  |  |  |         'allfiles' not supplied to constructor | 
					
						
							|  |  |  |       files | 
					
						
							|  |  |  |         list of filenames currently being built/filtered/manipulated | 
					
						
							|  |  |  |       allfiles | 
					
						
							|  |  |  |         complete list of files under consideration (ie. without any | 
					
						
							|  |  |  |         filtering applied) | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-12-06 20:51:35 +00:00
										 |  |  |     def __init__(self, | 
					
						
							|  |  |  |                  warn=None, | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |                  debug_print=None): | 
					
						
							| 
									
										
										
										
											2000-07-30 01:45:42 +00:00
										 |  |  |         # use standard warning and debug functions if no other given | 
					
						
							|  |  |  |         self.warn = warn or self.__warn | 
					
						
							|  |  |  |         self.debug_print = debug_print or self.__debug_print | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 01:45:42 +00:00
										 |  |  |         self.allfiles = None | 
					
						
							|  |  |  |         self.files = [] | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 01:45:42 +00:00
										 |  |  |     def set_allfiles (self, allfiles): | 
					
						
							|  |  |  |         self.allfiles = allfiles | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def findall (self, dir=os.curdir): | 
					
						
							|  |  |  |         self.allfiles = findall(dir) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # -- Fallback warning/debug functions ------------------------------ | 
					
						
							| 
									
										
										
										
											2001-12-06 20:51:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |     def __warn (self, msg): | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |         sys.stderr.write("warning: %s\n" % msg) | 
					
						
							| 
									
										
										
										
											2001-12-06 20:51:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |     def __debug_print (self, msg): | 
					
						
							|  |  |  |         """Print 'msg' to stdout if the global DEBUG (taken from the
 | 
					
						
							|  |  |  |         DISTUTILS_DEBUG environment variable) flag is true. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         from distutils.core import DEBUG | 
					
						
							|  |  |  |         if DEBUG: | 
					
						
							|  |  |  |             print msg | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 01:45:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # -- List-like methods --------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def append (self, item): | 
					
						
							|  |  |  |         self.files.append(item) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def extend (self, items): | 
					
						
							|  |  |  |         self.files.extend(items) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def sort (self): | 
					
						
							|  |  |  |         # Not a strict lexical sort! | 
					
						
							|  |  |  |         sortable_files = map(os.path.split, self.files) | 
					
						
							|  |  |  |         sortable_files.sort() | 
					
						
							|  |  |  |         self.files = [] | 
					
						
							|  |  |  |         for sort_tuple in sortable_files: | 
					
						
							|  |  |  |             self.files.append(apply(os.path.join, sort_tuple)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # -- Other miscellaneous utility methods --------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def remove_duplicates (self): | 
					
						
							|  |  |  |         # Assumes list has been sorted! | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |         for i in range(len(self.files)-1, 0, -1): | 
					
						
							| 
									
										
										
										
											2000-07-30 01:45:42 +00:00
										 |  |  |             if self.files[i] == self.files[i-1]: | 
					
						
							|  |  |  |                 del self.files[i] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # -- "File template" methods --------------------------------------- | 
					
						
							| 
									
										
										
										
											2001-12-06 20:51:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |     def _parse_template_line (self, line): | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |         words = string.split(line) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  |         action = words[0] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |         patterns = dir = dir_pattern = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if action in ('include', 'exclude', | 
					
						
							|  |  |  |                       'global-include', 'global-exclude'): | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |             if len(words) < 2: | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |                 raise DistutilsTemplateError, \ | 
					
						
							|  |  |  |                       "'%s' expects <pattern1> <pattern2> ..." % action | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |             patterns = map(convert_path, words[1:]) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |         elif action in ('recursive-include', 'recursive-exclude'): | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |             if len(words) < 3: | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |                 raise DistutilsTemplateError, \ | 
					
						
							|  |  |  |                       "'%s' expects <dir> <pattern1> <pattern2> ..." % action | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  |             dir = convert_path(words[1]) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |             patterns = map(convert_path, words[2:]) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |         elif action in ('graft', 'prune'): | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |             if len(words) != 2: | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |                 raise DistutilsTemplateError, \ | 
					
						
							|  |  |  |                      "'%s' expects a single <dir_pattern>" % action | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |             dir_pattern = convert_path(words[1]) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |             raise DistutilsTemplateError, "unknown action '%s'" % action | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 01:04:22 +00:00
										 |  |  |         return (action, patterns, dir, dir_pattern) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # _parse_template_line () | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-12-06 20:51:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def process_template_line (self, line): | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Parse the line: split it up, make sure the right number of words | 
					
						
							| 
									
										
										
										
											2000-07-30 00:36:25 +00:00
										 |  |  |         # is there, and return the relevant words.  'action' is always | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |         # defined: it's the first word of the line.  Which of the other | 
					
						
							|  |  |  |         # three are defined depends on the action; it'll be either | 
					
						
							|  |  |  |         # patterns, (dir and patterns), or (dir_pattern). | 
					
						
							|  |  |  |         (action, patterns, dir, dir_pattern) = self._parse_template_line(line) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # OK, now we know that the action is valid and we have the | 
					
						
							|  |  |  |         # right number of words on the line for that action -- so we | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |         # can proceed with minimal error-checking. | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  |         if action == 'include': | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |             self.debug_print("include " + string.join(patterns)) | 
					
						
							|  |  |  |             for pattern in patterns: | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |                 if not self.include_pattern(pattern, anchor=1): | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |                     self.warn("no files found matching '%s'" % pattern) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         elif action == 'exclude': | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |             self.debug_print("exclude " + string.join(patterns)) | 
					
						
							|  |  |  |             for pattern in patterns: | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |                 if not self.exclude_pattern(pattern, anchor=1): | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |                     self.warn( | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  |                         "no previously-included files found matching '%s'"% | 
					
						
							|  |  |  |                         pattern) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         elif action == 'global-include': | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |             self.debug_print("global-include " + string.join(patterns)) | 
					
						
							|  |  |  |             for pattern in patterns: | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |                 if not self.include_pattern(pattern, anchor=0): | 
					
						
							|  |  |  |                     self.warn(("no files found matching '%s' " + | 
					
						
							|  |  |  |                                "anywhere in distribution") % | 
					
						
							|  |  |  |                               pattern) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         elif action == 'global-exclude': | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |             self.debug_print("global-exclude " + string.join(patterns)) | 
					
						
							|  |  |  |             for pattern in patterns: | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |                 if not self.exclude_pattern(pattern, anchor=0): | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |                     self.warn(("no previously-included files matching '%s' " + | 
					
						
							|  |  |  |                                "found anywhere in distribution") % | 
					
						
							|  |  |  |                               pattern) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         elif action == 'recursive-include': | 
					
						
							|  |  |  |             self.debug_print("recursive-include %s %s" % | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |                              (dir, string.join(patterns))) | 
					
						
							|  |  |  |             for pattern in patterns: | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |                 if not self.include_pattern(pattern, prefix=dir): | 
					
						
							|  |  |  |                     self.warn(("no files found matching '%s' " + | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |                                 "under directory '%s'") % | 
					
						
							|  |  |  |                                (pattern, dir)) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         elif action == 'recursive-exclude': | 
					
						
							|  |  |  |             self.debug_print("recursive-exclude %s %s" % | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |                              (dir, string.join(patterns))) | 
					
						
							|  |  |  |             for pattern in patterns: | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  |                 if not self.exclude_pattern(pattern, prefix=dir): | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |                     self.warn(("no previously-included files matching '%s' " + | 
					
						
							|  |  |  |                                "found under directory '%s'") % | 
					
						
							|  |  |  |                               (pattern, dir)) | 
					
						
							| 
									
										
										
										
											2001-12-06 20:51:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  |         elif action == 'graft': | 
					
						
							|  |  |  |             self.debug_print("graft " + dir_pattern) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:36:25 +00:00
										 |  |  |             if not self.include_pattern(None, prefix=dir_pattern): | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |                 self.warn("no directories found matching '%s'" % dir_pattern) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         elif action == 'prune': | 
					
						
							|  |  |  |             self.debug_print("prune " + dir_pattern) | 
					
						
							|  |  |  |             if not self.exclude_pattern(None, prefix=dir_pattern): | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |                 self.warn(("no previously-included directories found " + | 
					
						
							|  |  |  |                            "matching '%s'") % | 
					
						
							|  |  |  |                           dir_pattern) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |             raise DistutilsInternalError, \ | 
					
						
							| 
									
										
										
										
											2000-07-30 00:08:13 +00:00
										 |  |  |                   "this cannot happen: invalid action '%s'" % action | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:21:36 +00:00
										 |  |  |     # process_template_line () | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 01:45:42 +00:00
										 |  |  |     # -- Filtering/selection methods ----------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:36:25 +00:00
										 |  |  |     def include_pattern (self, pattern, | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |                          anchor=1, prefix=None, is_regex=0): | 
					
						
							| 
									
										
										
										
											2000-07-30 00:36:25 +00:00
										 |  |  |         """Select strings (presumably filenames) from 'self.files' that
 | 
					
						
							|  |  |  |         match 'pattern', a Unix-style wildcard (glob) pattern.  Patterns | 
					
						
							|  |  |  |         are not quite the same as implemented by the 'fnmatch' module: '*' | 
					
						
							|  |  |  |         and '?'  match non-special characters, where "special" is platform- | 
					
						
							|  |  |  |         dependent: slash on Unix; colon, slash, and backslash on | 
					
						
							|  |  |  |         DOS/Windows; and colon on Mac OS. | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         If 'anchor' is true (the default), then the pattern match is more | 
					
						
							|  |  |  |         stringent: "*.py" will match "foo.py" but not "foo/bar.py".  If | 
					
						
							|  |  |  |         'anchor' is false, both of these will match. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         If 'prefix' is supplied, then only filenames starting with 'prefix' | 
					
						
							|  |  |  |         (itself a pattern) and ending with 'pattern', with anything in between | 
					
						
							|  |  |  |         them, will match.  'anchor' is ignored in this case. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         If 'is_regex' is true, 'anchor' and 'prefix' are ignored, and | 
					
						
							|  |  |  |         'pattern' is assumed to be either a string containing a regex or a | 
					
						
							|  |  |  |         regex object -- no translation is done, the regex is just compiled | 
					
						
							|  |  |  |         and used as-is. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Selected strings will be added to self.files. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Return 1 if files are found. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         files_found = 0 | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |         pattern_re = translate_pattern(pattern, anchor, prefix, is_regex) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:36:25 +00:00
										 |  |  |         self.debug_print("include_pattern: applying regex r'%s'" % | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |                          pattern_re.pattern) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # delayed loading of allfiles list | 
					
						
							| 
									
										
										
										
											2000-07-30 01:45:42 +00:00
										 |  |  |         if self.allfiles is None: | 
					
						
							|  |  |  |             self.findall() | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for name in self.allfiles: | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |             if pattern_re.search(name): | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |                 self.debug_print(" adding " + name) | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |                 self.files.append(name) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |                 files_found = 1 | 
					
						
							| 
									
										
										
										
											2001-12-06 20:51:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |         return files_found | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:36:25 +00:00
										 |  |  |     # include_pattern () | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def exclude_pattern (self, pattern, | 
					
						
							|  |  |  |                          anchor=1, prefix=None, is_regex=0): | 
					
						
							|  |  |  |         """Remove strings (presumably filenames) from 'files' that match
 | 
					
						
							|  |  |  |         'pattern'.  Other parameters are the same as for | 
					
						
							| 
									
										
										
										
											2001-12-06 20:51:35 +00:00
										 |  |  |         'include_pattern()', above. | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |         The list 'self.files' is modified in place. | 
					
						
							|  |  |  |         Return 1 if files are found. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         files_found = 0 | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |         pattern_re = translate_pattern(pattern, anchor, prefix, is_regex) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |         self.debug_print("exclude_pattern: applying regex r'%s'" % | 
					
						
							|  |  |  |                          pattern_re.pattern) | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |         for i in range(len(self.files)-1, -1, -1): | 
					
						
							|  |  |  |             if pattern_re.search(self.files[i]): | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |                 self.debug_print(" removing " + self.files[i]) | 
					
						
							|  |  |  |                 del self.files[i] | 
					
						
							|  |  |  |                 files_found = 1 | 
					
						
							| 
									
										
										
										
											2001-12-06 20:51:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |         return files_found | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # exclude_pattern () | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # class FileList | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # ---------------------------------------------------------------------- | 
					
						
							|  |  |  | # Utility functions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def findall (dir = os.curdir): | 
					
						
							|  |  |  |     """Find all files under 'dir' and return the list of full filenames
 | 
					
						
							|  |  |  |     (relative to 'dir'). | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     from stat import ST_MODE, S_ISREG, S_ISDIR, S_ISLNK | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     list = [] | 
					
						
							|  |  |  |     stack = [dir] | 
					
						
							|  |  |  |     pop = stack.pop | 
					
						
							|  |  |  |     push = stack.append | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while stack: | 
					
						
							|  |  |  |         dir = pop() | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |         names = os.listdir(dir) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for name in names: | 
					
						
							|  |  |  |             if dir != os.curdir:        # avoid the dreaded "./" syndrome | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |                 fullname = os.path.join(dir, name) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 fullname = name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Avoid excess stat calls -- just one will do, thank you! | 
					
						
							|  |  |  |             stat = os.stat(fullname) | 
					
						
							|  |  |  |             mode = stat[ST_MODE] | 
					
						
							|  |  |  |             if S_ISREG(mode): | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |                 list.append(fullname) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |             elif S_ISDIR(mode) and not S_ISLNK(mode): | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |                 push(fullname) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return list | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def glob_to_re (pattern): | 
					
						
							|  |  |  |     """Translate a shell-like glob pattern to a regular expression; return
 | 
					
						
							|  |  |  |     a string containing the regex.  Differs from 'fnmatch.translate()' in | 
					
						
							|  |  |  |     that '*' does not match "special characters" (which are | 
					
						
							|  |  |  |     platform-specific). | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |     pattern_re = fnmatch.translate(pattern) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # '?' and '*' in the glob pattern become '.' and '.*' in the RE, which | 
					
						
							|  |  |  |     # IMHO is wrong -- '?' and '*' aren't supposed to match slash in Unix, | 
					
						
							|  |  |  |     # and by extension they shouldn't match such "special characters" under | 
					
						
							|  |  |  |     # any OS.  So change all non-escaped dots in the RE to match any | 
					
						
							|  |  |  |     # character except the special characters. | 
					
						
							|  |  |  |     # XXX currently the "special characters" are just slash -- i.e. this is | 
					
						
							|  |  |  |     # Unix-only. | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |     pattern_re = re.sub(r'(^|[^\\])\.', r'\1[^/]', pattern_re) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |     return pattern_re | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # glob_to_re () | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def translate_pattern (pattern, anchor=1, prefix=None, is_regex=0): | 
					
						
							|  |  |  |     """Translate a shell-like wildcard pattern to a compiled regular
 | 
					
						
							|  |  |  |     expression.  Return the compiled regex.  If 'is_regex' true, | 
					
						
							|  |  |  |     then 'pattern' is directly compiled to a regex (if it's a string) | 
					
						
							|  |  |  |     or just returned as-is (assumes it's a regex object). | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if is_regex: | 
					
						
							|  |  |  |         if type(pattern) is StringType: | 
					
						
							|  |  |  |             return re.compile(pattern) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return pattern | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if pattern: | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |         pattern_re = glob_to_re(pattern) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         pattern_re = '' | 
					
						
							| 
									
										
										
										
											2001-12-06 20:51:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |     if prefix is not None: | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |         prefix_re = (glob_to_re(prefix))[0:-1] # ditch trailing $ | 
					
						
							|  |  |  |         pattern_re = "^" + os.path.join(prefix_re, ".*" + pattern_re) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  |     else:                               # no prefix -- respect anchor flag | 
					
						
							|  |  |  |         if anchor: | 
					
						
							|  |  |  |             pattern_re = "^" + pattern_re | 
					
						
							| 
									
										
										
										
											2001-12-06 20:51:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-26 02:12:31 +00:00
										 |  |  |     return re.compile(pattern_re) | 
					
						
							| 
									
										
										
										
											2000-07-30 00:04:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # translate_pattern () |