9aa93057dd3d2ddb4d6691305e538624bf6c9b70
[update-copyright.git] / update_copyright / utils.py
1 # Copyright
2
3 import difflib as _difflib
4 import os as _os
5 import os.path as _os_path
6 import textwrap as _textwrap
7 import time as _time
8
9 from . import LOG as _LOG
10
11
12 def long_author_formatter(copyright_year_string, authors):
13     """
14     >>> print '\\n'.join(long_author_formatter(
15     ...     copyright_year_string='Copyright (C) 1990-2010',
16     ...     authors=['Jack', 'Jill', 'John']))
17     Copyright (C) 1990-2010 Jack
18                             Jill
19                             John
20     """
21     lines = ['%s %s' % (copyright_year_string, authors[0])]
22     for author in authors[1:]:
23         lines.append(' '*(len(copyright_year_string)+1) + author)
24     return lines
25
26 def short_author_formatter(copyright_year_string, authors):
27     """
28     >>> print '\\n'.join(short_author_formatter(
29     ...     copyright_year_string='Copyright (C) 1990-2010',
30     ...     authors=['Jack', 'Jill', 'John']*5))
31     Copyright (C) 1990-2010 Jack, Jill, John, Jack, Jill, John, Jack, Jill, John, Jack, Jill, John, Jack, Jill, John
32     """
33     blurb = '%s %s' % (copyright_year_string, ', '.join(authors))
34     return [blurb]
35
36 def copyright_string(original_year, final_year, authors, text, info={},
37                      author_format_fn=long_author_formatter,
38                      formatter_kwargs={}, prefix='', wrap=True,
39                      **wrap_kwargs):
40     """
41     >>> print(copyright_string(original_year=2005, final_year=2005,
42     ...                        authors=['A <a@a.com>', 'B <b@b.edu>'],
43     ...                        text=['BLURB',], prefix='# '
44     ...                        )) # doctest: +REPORT_UDIFF
45     # Copyright (C) 2005 A <a@a.com>
46     #                    B <b@b.edu>
47     #
48     # BLURB
49     >>> print(copyright_string(original_year=2005, final_year=2009,
50     ...                        authors=['A <a@a.com>', 'B <b@b.edu>'],
51     ...                        text=['BLURB',]
52     ...                        )) # doctest: +REPORT_UDIFF
53     Copyright (C) 2005-2009 A <a@a.com>
54                             B <b@b.edu>
55     <BLANKLINE>
56     BLURB
57     >>> print(copyright_string(original_year=2005, final_year=2005,
58     ...                        authors=['A <a@a.com>', 'B <b@b.edu>'],
59     ...                        text=['This file is part of %(program)s.',],
60     ...                        author_format_fn=short_author_formatter,
61     ...                        info={'program':'update-copyright'},
62     ...                        width=25,
63     ...                        )) # doctest: +REPORT_UDIFF
64     Copyright (C) 2005 A <a@a.com>, B <b@b.edu>
65     <BLANKLINE>
66     This file is part of
67     update-copyright.
68     >>> print(copyright_string(original_year=2005, final_year=2005,
69     ...                        authors=['A <a@a.com>', 'B <b@b.edu>'],
70     ...                        text=[('This file is part of %(program)s.  '*3
71     ...                               ).strip(),],
72     ...                        info={'program':'update-copyright'},
73     ...                        author_format_fn=short_author_formatter,
74     ...                        wrap=False,
75     ...                        )) # doctest: +REPORT_UDIFF
76     Copyright (C) 2005 A <a@a.com>, B <b@b.edu>
77     <BLANKLINE>
78     This file is part of update-copyright.  This file is part of update-copyright.  This file is part of update-copyright.
79     """
80     for key in ['initial_indent', 'subsequent_indent']:
81         if key not in wrap_kwargs:
82             wrap_kwargs[key] = prefix
83
84     if original_year == final_year:
85         date_range = '%s' % original_year
86     else:
87         date_range = '%s-%s' % (original_year, final_year)
88     copyright_year_string = 'Copyright (C) %s' % date_range
89
90     lines = author_format_fn(copyright_year_string, authors,
91                              **formatter_kwargs)
92     for i,line in enumerate(lines):
93         lines[i] = prefix + line
94
95     for i,paragraph in enumerate(text):
96         try:
97             text[i] = paragraph % info
98         except ValueError, e:
99             _LOG.error(
100                 "{}: can't format {} with {}".format(e, paragraph, info))
101             raise
102         except TypeError, e:
103             _LOG.error(
104                 ('{}: copright text must be a list of paragraph strings, '
105                  'not {}').format(e, repr(text)))
106             raise
107
108     if wrap == True:
109         text = [_textwrap.fill(p, **wrap_kwargs) for p in text]
110     else:
111         assert wrap_kwargs['subsequent_indent'] == '', \
112             wrap_kwargs['subsequent_indent']
113     sep = '\n%s\n' % prefix.rstrip()
114     return sep.join(['\n'.join(lines)] + text)
115
116 def tag_copyright(contents, tag=None):
117     """
118     >>> contents = '''Some file
119     ... bla bla
120     ... # Copyright (copyright begins)
121     ... # (copyright continues)
122     ... # bla bla bla
123     ... (copyright ends)
124     ... bla bla bla
125     ... '''
126     >>> print tag_copyright(contents, tag='-xyz-CR-zyx-')
127     Some file
128     bla bla
129     -xyz-CR-zyx-
130     (copyright ends)
131     bla bla bla
132     <BLANKLINE>
133     """
134     lines = []
135     incopy = False
136     for line in contents.splitlines():
137         if incopy == False and line.startswith('# Copyright'):
138             incopy = True
139             lines.append(tag)
140         elif incopy == True and not line.startswith('#'):
141             incopy = False
142         if incopy == False:
143             lines.append(line.rstrip('\n'))
144     return '\n'.join(lines)+'\n'
145
146 def update_copyright(contents, tag=None, **kwargs):
147     """
148     >>> contents = '''Some file
149     ... bla bla
150     ... # Copyright (copyright begins)
151     ... # (copyright continues)
152     ... # bla bla bla
153     ... (copyright ends)
154     ... bla bla bla
155     ... '''
156     >>> print update_copyright(contents, original_year=2008,
157     ...                        authors=['Jack', 'Jill'],
158     ...                        text=['BLURB',], prefix='# ', tag='--tag--'
159     ...     ) # doctest: +ELLIPSIS, +REPORT_UDIFF
160     Some file
161     bla bla
162     # Copyright (C) 2008-... Jack
163     #                         Jill
164     #
165     # BLURB
166     (copyright ends)
167     bla bla bla
168     <BLANKLINE>
169     """
170     current_year = _time.gmtime()[0]
171     string = copyright_string(final_year=current_year, **kwargs)
172     contents = tag_copyright(contents=contents, tag=tag)
173     return contents.replace(tag, string)
174
175 def get_contents(filename):
176     if _os_path.isfile(filename):
177         f = open(filename, 'r')
178         contents = f.read()
179         f.close()
180         return contents
181     return None
182
183 def set_contents(filename, contents, original_contents=None, dry_run=False):
184     if original_contents is None:
185         original_contents = get_contents(filename=filename)
186     _LOG.debug('check contents of {}'.format(filename))
187     if contents != original_contents:
188         if original_contents is None:
189             _LOG.info('creating {}'.format(filename))
190         else:
191             _LOG.info('updating {}'.format(filename))
192             _LOG.debug('\n'.join(
193                     _difflib.unified_diff(
194                         original_contents.splitlines(), contents.splitlines(),
195                         fromfile=_os_path.normpath(
196                             _os_path.join('a', filename)),
197                         tofile=_os_path.normpath(_os_path.join('b', filename)),
198                         n=3, lineterm='')))
199         if dry_run == False:
200             f = file(filename, 'w')
201             f.write(contents)
202             f.close()
203     _LOG.debug('no change in {}'.format(filename))
204
205 def list_files(root='.'):
206     for dirpath,dirnames,filenames in _os.walk(root):
207         for filename in filenames:
208             yield _os_path.join(root, dirpath, filename)