1from __future__ import print_function 2from __future__ import absolute_import 3# Written by Ross Cohen 4# Maintained by Chris Hutchinson 5# see LICENSE.txt for license information 6 7from builtins import object 8from .client_helpers import children_count 9from .client_helpers import filename_to_handle 10import fnmatch 11import os, sys 12from os import path 13from .path import subpath 14import re 15 16class Glob(object): 17 def __init__(self, co, files): 18 self.co = co 19 self.local = co.local 20 21 if sys.platform == 'win32': 22 self._glob_cache = {} 23 unglobbedfiles = files 24 files = [] 25 for file in unglobbedfiles: 26 files += self._glob(file) 27 del self._glob_cache 28 29 # normalize the filenames 30 self.files = [] 31 for file in files: 32 try: 33 self.files.append(subpath(self.local, file)[1]) 34 except ValueError: 35 print('warning - %s is not under the repository' % (file,)) 36 return 37 38 def fs_walk(self, expand=1): 39 for file in self.files: 40 parent, name = path.split(file) 41 if name == '...': 42 if expand: 43 for lfile in self._fs_expand(parent): 44 yield (lfile, 1) 45 continue 46 47 if not path.exists(path.join(self.local, file)): 48 print('warning - %s does not exist' % (file,)) 49 continue 50 51 yield (file, 0) 52 53 return 54 55 def db_walk(self, deletes=0, txn=None): 56 for file in self.files: 57 parent, name = path.split(file) 58 if name == '...': 59 for lhandle in self._db_expand(parent, deletes, txn): 60 yield (lhandle, 1) 61 continue 62 63 handle = filename_to_handle(self.co, file, txn, deletes=deletes) 64 if handle is None: 65 print('warning - %s is not in the repository' % (file,)) 66 continue 67 68 yield (handle, 0) 69 70 return 71 72 def _fs_expand(self, local): 73 root_cmp = path.join(self.local, '.cdv') 74 filter = path.join(self.local, '.cdv', '') 75 76 root_len = len(self.local + path.sep) 77 filter_len = len(filter) 78 79 for root, dirs, files, in os.walk(path.join(self.local, local)): 80 if root == root_cmp: 81 dirs[:] = [] 82 continue 83 84 if root[:filter_len] == filter: 85 dirs[:] = [] 86 continue 87 88 nroot = root[root_len:] 89 if nroot != local: 90 yield nroot 91 92 for file in files: 93 yield path.join(nroot, file) 94 95 return 96 97 def _db_expand(self, local, deletes, txn): 98 handle = filename_to_handle(self.co, local, txn) 99 dirs = [handle] 100 while len(dirs): 101 lhandle = dirs.pop() 102 103 children = children_count(self.co, lhandle, txn, deletes=deletes) 104 dirs.extend(children) 105 106 for handle in children: 107 yield handle 108 109 return 110 111 def _glob(self, pathname): 112 if not self._has_magic(pathname): 113 return [pathname] 114 dirname, basename = os.path.split(pathname) 115 if not dirname: 116 return self._glob1(os.curdir, basename) 117 elif self._has_magic(dirname): 118 list = self._glob(dirname) 119 else: 120 list = [dirname] 121 if not self._has_magic(basename): 122 result = [] 123 for dirname in list: 124 if basename or os.path.isdir(dirname): 125 name = os.path.join(dirname, basename) 126 if os.path.lexists(name): 127 result.append(name) 128 else: 129 result = [] 130 for dirname in list: 131 sublist = self._glob1(dirname, basename) 132 for name in sublist: 133 result.append(os.path.join(dirname, name)) 134 if len(result) == 0: 135 result.append(pathname) 136 return result 137 138 def _glob1(self, dirname, pattern): 139 if not dirname: dirname = os.curdir 140 if dirname in self._glob_cache: 141 names = self._glob_cache[dirname] 142 else: 143 try: 144 names = os.listdir(dirname) 145 except os.error: 146 return [] 147 self._glob_cache[dirname] = names 148 if pattern[0]!='.': 149 names=[x for x in names if x[0]!='.'] 150 return fnmatch.filter(names,pattern) 151 152 153 _magic_check = re.compile('[*?[]') 154 155 def _has_magic(self, s): 156 return self._magic_check.search(s) is not None 157