44 Targets ,
55 filenameof ,
66 filenamesof ,
7- cwdStack ,
7+ getcwd ,
88 error ,
99 simplerule ,
10- G
10+ G ,
1111)
12- from os .path import relpath , splitext , join , basename , isfile
12+ from os .path import relpath , splitext , join , basename , isfile , normpath
13+ from os import walk
1314from glob import iglob
1415import fnmatch
1516import subprocess
1617import shutil
18+ import re
19+ import functools
1720
1821
1922def filenamesmatchingof (xs , pattern ):
@@ -35,9 +38,64 @@ def collectattrs(*, targets, name, initial=[]):
3538 return sorted (s )
3639
3740
41+ @functools .cache
42+ def _glob_to_re (glob_str ):
43+ opts = re .compile ("([.]|[*][*]/|[*]|[?])|(.)" )
44+ out = ""
45+ for pattern_match , literal_text in opts .findall (glob_str ):
46+ if pattern_match == "." :
47+ out += "[.]"
48+ elif pattern_match == "**/" :
49+ out += "(?:.*/)?"
50+ elif pattern_match == "*" :
51+ out += "[^/]*"
52+ elif pattern_match == "?" :
53+ out += "."
54+ elif literal_text :
55+ out += literal_text
56+ return re .compile (out )
57+
58+
59+ def _glob_filter (paths , pattern ):
60+ r = _glob_to_re (pattern )
61+ for f in paths :
62+ if r .match (f ):
63+ yield f
64+
65+
66+ def _glob_matches (path , pattern ):
67+ r = _glob_to_re (pattern )
68+ return r .match (path )
69+
70+
71+ def glob (include = ["*" ], exclude = [], dir = None , relative_to = "." ):
72+ if not dir :
73+ dir = getcwd ()
74+ if dir .startswith ("./" ):
75+ dir = normpath (join (getcwd (), dir ))
76+ if relative_to .startswith ("./" ):
77+ relative_to = normpath (join (getcwd (), relative_to ))
78+
79+ def iterate ():
80+ for dirpath , dirnames , filenames in walk (
81+ dir , topdown = True , followlinks = True
82+ ):
83+ dirpath = relpath (dirpath , dir )
84+ filenames = [normpath (join (dirpath , f )) for f in filenames ]
85+ matching = set ()
86+ for p in include :
87+ matching .update (_glob_filter (filenames , p ))
88+ for p in exclude :
89+ matching = [n for n in matching if not _glob_matches (n , p )]
90+ for f in matching :
91+ yield normpath (relpath (join (dir , f ), relative_to ))
92+
93+ return list (iterate ())
94+
95+
3896def itemsof (pattern , root = None , cwd = None ):
3997 if not cwd :
40- cwd = cwdStack [ - 1 ]
98+ cwd = getcwd ()
4199 if not root :
42100 root = "."
43101
0 commit comments