/
find-in-repository.py
executable file
·110 lines (95 loc) · 3.74 KB
/
find-in-repository.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/env python3
from optparse import OptionParser
import os
import re
from subprocess import Popen, PIPE
import sys
# A small script for finding files in a git repository. This is
# mostly useful for inding files that you know appeared in the history
# of some branch at some point, but can't remember where...
def command_to_lines(command,nul=False):
p = Popen(command,stdout=PIPE)
output = p.communicate()[0]
if p.returncode != 0:
print("'{}' failed.".format(' '.join(command),file=sys.stderr))
sys.exit(1)
str_output = output.decode()
if nul:
return str_output.split('\0')
else:
return str_output.splitlines(False)
parser = OptionParser(usage="Usage: %prog [OPTIONS] PATH-REGEXP")
parser.add_option('--start-ref',
dest="start_ref",
metavar="[REF]",
default=None,
help="instead of going through all refs, just do [REF]")
parser.add_option('--start-tree',
dest="start_tree",
metavar="[TREE]",
default=None,
help="instead of going through all refs, start at the tree object [TREE]")
parser.add_option('--all-history','-a',
action="store_true",
dest="all_history",
default=False,
help="when starting from refs, look through their complete history")
options,args = parser.parse_args()
if len(args) != 1:
parser.print_help()
sys.exit(1)
path_regexp = args[0]
all_refs = {}
if options.start_ref and options.start_tree:
print("You can't specify both a start ref and a start tree",file=sys.stderr)
sys.exit(1)
if options.start_tree and options.all_history:
print("You can't search all history when starting from a particular tree",file=sys.stderr)
sys.exit(1)
if options.start_ref:
for line in command_to_lines(['git','rev-parse',options.start_ref]):
m = re.search('(\S+)',line)
if m:
object_name = m.group(1)
all_refs.setdefault(object_name,[])
all_refs[object_name].append(options.start_ref)
else:
for line in command_to_lines(["git","for-each-ref"]):
m = re.search('(\S+)\s+\S+\s+(\S+)',line)
if m:
object_name = m.group(1)
all_refs.setdefault(object_name,[])
all_refs[object_name].append(m.group(2))
# Cache all already explored trees:
trees_dictionary = {}
def tree_to_recursive_list(tree):
if tree in trees_dictionary:
return trees_dictionary[tree]
files = []
for line in command_to_lines(["git","ls-tree","-z",tree],nul=True):
m = re.search('(\S+)\s+(\S+)\s+(\S+)\s+(.*)',line)
if m:
mode, object_type, object_name, entry_name = m.groups()
mode_int = int(mode,8) % 0o1000
if object_type == "tree":
files_in_tree = tree_to_recursive_list(object_name)
for t in files_in_tree:
files.append((t[0],os.path.join(entry_name,t[1]),t[2]))
elif object_type == "blob":
files.append((object_name,entry_name,mode_int))
trees_dictionary.setdefault(tree,files)
return files
def deal_with_tree(tree,prefix,d='.'):
for t in tree_to_recursive_list(tree):
if re.search(path_regexp,t[1]):
print("{} {} {}".format(prefix,t[0],t[1]))
if options.start_tree:
deal_with_tree(options.start_tree,'None ()')
else:
for r in all_refs:
prefix = "{} ({})".format(r,','.join(all_refs[r]))
deal_with_tree(r,prefix,r)
if options.all_history:
for commit in command_to_lines(["git","log","--format=%H",r])[1:]:
prefix = commit+" ()"
deal_with_tree(commit,prefix,commit)