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