1+ import subprocess
2+ import os
3+
4+ # Used for output suppression when calling subprocess functions; see
5+ # http://stackoverflow.com/questions/10251391/suppressing-output-in-python-subprocess-call
6+ devnull = open (os .devnull , 'w' )
7+
8+ def all_ignored_files (folder ):
9+ """
10+ Returns a list (without duplicates, in the case of weird repo-nesting) of
11+ all files within the given folder that are git ignored.
12+
13+ The folder itself need not be the top level of a git repo, nor even within
14+ a git repo.
15+ """
16+
17+ all_ignored_files = set ()
18+
19+ # First find all repos CONTAINED in this folder:
20+ repos = set (find_git_repos (folder ))
21+
22+ # Then, additionally, if this folder is itself contained within a repo,
23+ # find the .git folder of the repo containing it:
24+ if is_in_git_repo (folder ):
25+ repos .add (parent_repo_path (folder ))
26+
27+ # Now we find all the ignored files in any of the above repos
28+ for git_repo in repos :
29+ ignored_files = list_ignored_files (git_repo )
30+ all_ignored_files .update (ignored_files )
31+
32+ return list (all_ignored_files )
33+
34+ def is_in_git_repo (folder ):
35+ """
36+ Returns true if the given folder is contained within a git repo
37+ """
38+
39+ exit_code = subprocess .call (
40+ ["git" , "rev-parse" , "--is-inside-work-tree" ],
41+ cwd = folder ,
42+ stdout = devnull ,
43+ stderr = devnull
44+ )
45+
46+ return exit_code == 0
47+
48+ def parent_repo_path (folder ):
49+ """
50+ Takes the path to a folder contained within a git repo, and returns the parent repo.
51+ """
52+
53+ return subprocess .Popen (
54+ ['git' , 'rev-parse' , '--show-toplevel' ],
55+ stdout = subprocess .PIPE ,
56+ cwd = folder
57+ ).stdout .read ().strip ()
58+
59+ def find_git_repos (folder ):
60+ """
61+ Returns a list of all git repos within the given ancestor folder.
62+ """
63+
64+ # Command for finding git repos nicked from
65+ # http://sixarm.com/about/git-how-to-find-git-repository-directories.html
66+ command_output = subprocess .Popen (
67+ ['find' , folder , '-type' , 'd' , '-name' , '.git' ],
68+ stdout = subprocess .PIPE
69+ ).stdout .read ()
70+
71+ if command_output .isspace () or command_output == '' :
72+ return []
73+
74+ dot_git_folders = command_output .strip ().split ('\n ' )
75+
76+ return [path .replace ('/.git' , '' ) for path in dot_git_folders ]
77+
78+ def list_ignored_files (git_repo ):
79+ """
80+ Takes the path of a git repo and lists all ignored files in the repo.
81+ """
82+
83+ # Trick for listing ignored files nicked from
84+ # http://stackoverflow.com/a/2196755/1709587
85+ command_output = subprocess .Popen (
86+ ['git' , 'clean' , '-ndX' ],
87+ stdout = subprocess .PIPE ,
88+ cwd = git_repo
89+ ).stdout .read ()
90+
91+ if command_output .isspace () or command_output == '' :
92+ return []
93+
94+ lines = command_output .strip ().split ('\n ' )
95+ # Each line in `lines` now looks something like:
96+ # "Would remove foo/bar/yourfile.txt"
97+
98+ relative_paths = [line .replace ('Would remove ' , '' , 1 ) for line in lines ]
99+ absolute_paths = [git_repo + '/' + path for path in relative_paths ]
100+
101+ return absolute_paths
0 commit comments