22from pathlib import Path
33from typing import Any , Dict , Iterable , Iterator , List , Optional , Pattern , Tuple
44
5+ import pathspec
6+
57try :
68 import rich_click as click
79except ImportError :
810 import click
911
1012import tomli
11- from pathspec import PathSpec
1213
1314DEFAULT_EXCLUDES = r"/(\.direnv|\.eggs|\.git|\.hg|\.nox|\.tox|\.venv|venv|\.svn)/"
1415INCLUDE_EXT = (".robot" , ".resource" )
@@ -39,7 +40,7 @@ def find_source_config_file(src: Path, ignore_git_dir: bool = False) -> Optional
3940
4041
4142@lru_cache ()
42- def find_project_root (srcs : Iterable [str ], ignore_git_dir : bool = False ) -> Path :
43+ def find_project_root (srcs : Tuple [str ], ignore_git_dir : bool = False ) -> Path :
4344 """Return a directory containing .git, or robotidy.toml.
4445 That directory will be a common parent of all files and directories
4546 passed in `srcs`.
@@ -85,33 +86,46 @@ def read_pyproject_config(config_path: Path) -> Dict[str, Any]:
8586
8687
8788@lru_cache ()
88- def get_gitignore (root : Path ) -> PathSpec :
89+ def get_gitignore (root : Path ) -> pathspec . PathSpec :
8990 """Return a PathSpec matching gitignore content if present."""
9091 gitignore = root / ".gitignore"
9192 lines : List [str ] = []
9293 if gitignore .is_file ():
9394 with gitignore .open (encoding = "utf-8" ) as gf :
9495 lines = gf .readlines ()
95- return PathSpec .from_lines ("gitwildmatch" , lines )
96+ return pathspec . PathSpec .from_lines (pathspec . patterns . GitWildMatchPattern , lines )
9697
9798
9899def should_parse_path (
99- path : Path , exclude : Optional [Pattern [str ]], extend_exclude : Optional [Pattern [str ]], gitignore : Optional [PathSpec ]
100+ path : Path ,
101+ root_parent : Path ,
102+ exclude : Optional [Pattern [str ]],
103+ extend_exclude : Optional [Pattern [str ]],
104+ gitignore : Optional [pathspec .PathSpec ],
100105) -> bool :
101106 normalized_path = str (path )
102107 for pattern in (exclude , extend_exclude ):
103108 match = pattern .search (normalized_path ) if pattern else None
104109 if bool (match and match .group (0 )):
105110 return False
106- if gitignore is not None and gitignore .match_file (path ):
107- return False
111+ if gitignore is not None :
112+ relative_path = get_path_relative_to_project_root (path , root_parent )
113+ if gitignore .match_file (relative_path ):
114+ return False
108115 if path .is_file ():
109116 return path .suffix in INCLUDE_EXT
110117 if exclude and exclude .match (path .name ):
111118 return False
112119 return True
113120
114121
122+ def get_path_relative_to_project_root (path : Path , root_parent : Path ) -> Path :
123+ try :
124+ return path .relative_to (root_parent )
125+ except ValueError :
126+ return path
127+
128+
115129def get_paths (
116130 src : Tuple [str , ...], exclude : Optional [Pattern ], extend_exclude : Optional [Pattern ], skip_gitignore : bool
117131):
@@ -126,12 +140,13 @@ def get_paths(
126140 sources .add ("-" )
127141 continue
128142 path = Path (s ).resolve ()
129- if not should_parse_path (path , exclude , extend_exclude , gitignore ):
143+ root_parent = root .parent if root .parent else root
144+ if not should_parse_path (path , root_parent , exclude , extend_exclude , gitignore ):
130145 continue
131146 if path .is_file ():
132147 sources .add (path )
133148 elif path .is_dir ():
134- sources .update (iterate_dir ((path ,), exclude , extend_exclude , gitignore ))
149+ sources .update (iterate_dir ((path ,), exclude , extend_exclude , root_parent , gitignore ))
135150 elif s == "-" :
136151 sources .add (path )
137152
@@ -142,16 +157,18 @@ def iterate_dir(
142157 paths : Iterable [Path ],
143158 exclude : Optional [Pattern ],
144159 extend_exclude : Optional [Pattern ],
145- gitignore : Optional [PathSpec ],
160+ root_parent : Path ,
161+ gitignore : Optional [pathspec .PathSpec ],
146162) -> Iterator [Path ]:
147163 for path in paths :
148- if not should_parse_path (path , exclude , extend_exclude , gitignore ):
164+ if not should_parse_path (path , root_parent , exclude , extend_exclude , gitignore ):
149165 continue
150166 if path .is_dir ():
151167 yield from iterate_dir (
152168 path .iterdir (),
153169 exclude ,
154170 extend_exclude ,
171+ root_parent ,
155172 gitignore + get_gitignore (path ) if gitignore is not None else None ,
156173 )
157174 elif path .is_file ():
0 commit comments