7 from file_types
import lang_type
, find_files
9 mode_line
= re
.compile('(-\*- *mode:.* *-\*-)')
10 shell_comment
= re
.compile(r
'^\s*#')
11 lisp_comment
= re
.compile(r
';')
12 cpp_comment
= re
.compile(r
'//')
13 c_comment_start
= re
.compile(r
'/\*')
14 c_comment_end
= re
.compile(r
'\*/')
15 def find_copyright_block(lines
, lang_type
):
17 if lang_type
in ('python', 'make', 'shell', 'perl', 'scons'):
18 for i
,line
in enumerate(lines
):
19 if i
== 0 and (line
.startswith('#!') or mode_line
.search(line
)):
22 if shell_comment
.search(line
):
32 elif lang_type
in ('lisp', ):
33 for i
,line
in enumerate(lines
):
34 if i
== 0 and mode_line
.search(line
):
37 if lisp_comment
.search(line
):
47 elif lang_type
in ('C', 'C++', 'swig', 'isa', 'asm', 'slicc',
50 for i
,line
in enumerate(lines
):
51 if i
== 0 and mode_line
.search(line
):
55 assert start
is not None, 'on line %d' % (i
+ 1)
56 match
= c_comment_end
.search(line
)
62 cpp_match
= cpp_comment
.search(line
)
63 c_match
= c_comment_start
.search(line
)
66 assert not c_match
, 'on line %d' % (i
+ 1)
67 if line
[:cpp_match
.start()].strip():
73 text
= line
[cpp_match
.end():].lstrip()
74 if text
.startswith("Copyright") > 0:
79 assert start
is not None, 'on line %d' % (i
+ 1)
88 assert mode
is None, 'on line %d' % (i
+ 1)
92 if mode
is None and line
.strip():
96 raise AttributeError("Could not handle language %s" % lang_type
)
98 date_range_re
= re
.compile(r
'([0-9]{4})\s*-\s*([0-9]{4})')
99 def process_dates(dates
):
100 dates
= [ d
.strip() for d
in dates
.split(',') ]
104 match
= date_range_re
.match(date
)
106 f
,l
= [ int(d
) for d
in match
.groups() ]
107 for i
in range(f
, l
+1):
119 re
.compile(r
'Copyright (\([cC]\)) ([-, 0-9]+)[\s*#/]*([A-z-,. ]+)',
122 authors_re
= re
.compile(r
'^[\s*#/]*Authors:\s*([A-z .]+)\s*$')
123 more_authors_re
= re
.compile(r
'^[\s*#/]*([A-z .]+)\s*$')
126 def get_data(lang_type
, lines
):
129 for start
,end
in find_copyright_block(lines
, lang_type
):
130 joined
= ''.join(lines
[start
:end
+1])
131 match
= copyright_re
.search(joined
)
135 c
,dates
,owner
= match
.groups()
136 dates
= dates
.strip()
137 owner
= owner
.strip()
139 all_owners
.add(owner
)
141 dates
= process_dates(dates
)
148 for i
in range(start
,end
+1):
151 match
= authors_re
.search(line
)
153 authors
.append(match
.group(1).strip())
155 match
= more_authors_re
.search(line
)
157 for j
in range(i
, end
+1):
158 line
= lines
[j
].strip()
162 if line
.startswith('//'):
163 line
= line
[2:].lstrip()
168 authors
.append(match
.group(1).strip())
170 info
= (owner
, dates
, authors
, start
, end
)
180 def add_output(first
, second
):
182 output
.append('%d' % (first
))
184 output
.append('%d-%d' % (first
, second
))
190 if next
== second
+ 1:
193 add_output(first
, second
)
197 add_output(first
, second
)
199 return ','.join(output
)
201 usage_str
= """usage:
202 %s [-v] <directory>"""
205 print(usage_str
% sys
.argv
[0])
206 if exitcode
is not None:
209 if __name__
== '__main__':
216 opts
, args
= getopt
.getopt(sys
.argv
[1:], "ci:v")
217 except getopt
.GetoptError
:
231 if os
.path
.isfile(base
):
232 files
+= [ (base
, lang_type(base
)) ]
233 elif os
.path
.isdir(base
):
234 files
+= find_files(base
)
236 raise AttributeError("can't access '%s'" % base
)
241 for filename
, lang
in files
:
242 f
= file(filename
, 'r')
243 lines
= f
.readlines()
247 lines
= [ line
.rstrip('\r\n') for line
in lines
]
249 lt
= lang_type(filename
, lines
[0])
251 data
= get_data(lt
, lines
)
252 except Exception as e
:
255 e
.args
= ('%s (%s))' % (e
, filename
), )
256 print("could not parse %s: %s" % (filename
, e
))
259 for owner
, dates
, authors
, start
, end
in data
:
260 if owner
not in copyrights
:
261 copyrights
[owner
] = set()
262 if owner
not in counts
:
265 copyrights
[owner
] |
= dates
268 info
= [ (counts
[o
], d
, o
) for o
,d
in list(copyrights
.items()) ]
270 for count
,dates
,owner
in sorted(info
, reverse
=True):
272 owner
= '%s (%s files)' % (owner
, count
)
273 print('Copyright (c) %s %s' % (datestr(dates
), owner
))