| # -*- coding:utf-8 -*- |
| |
| |
| import difflib |
| import io |
| import re |
| from tempfile import mkstemp |
| |
| from portage import _encodings |
| from portage import _unicode_decode |
| from portage import _unicode_encode |
| from portage import os |
| from portage import shutil |
| from portage import util |
| |
| |
| _copyright_re1 = re.compile(br'^(# Copyright \d\d\d\d)-\d\d\d\d ') |
| _copyright_re2 = re.compile(br'^(# Copyright )(\d\d\d\d) ') |
| |
| |
| class _copyright_repl(object): |
| __slots__ = ('year',) |
| |
| def __init__(self, year): |
| self.year = year |
| |
| def __call__(self, matchobj): |
| if matchobj.group(2) == self.year: |
| return matchobj.group(0) |
| else: |
| return matchobj.group(1) + matchobj.group(2) + \ |
| b'-' + self.year + b' ' |
| |
| |
| def update_copyright_year(year, line): |
| """ |
| These two regexes are taken from echangelog |
| update_copyright(), except that we don't hardcode |
| 1999 here (in order to be more generic). |
| """ |
| is_bytes = isinstance(line, bytes) |
| if is_bytes: |
| if not line.startswith(b'# Copyright '): |
| return line |
| else: |
| if not line.startswith('# Copyright '): |
| return line |
| |
| year = _unicode_encode(year) |
| line = _unicode_encode(line) |
| |
| line = _copyright_re1.sub(br'\1-' + year + b' ', line) |
| line = _copyright_re2.sub(_copyright_repl(year), line) |
| if not is_bytes: |
| line = _unicode_decode(line) |
| return line |
| |
| |
| def update_copyright(fn_path, year, pretend=False): |
| """ |
| Check file for a Copyright statement, and update its year. The |
| patterns used for replacing copyrights are taken from echangelog. |
| Only the first lines of each file that start with a hash ('#') are |
| considered, until a line is found that doesn't start with a hash. |
| Files are read and written in binary mode, so that this function |
| will work correctly with files encoded in any character set, as |
| long as the copyright statements consist of plain ASCII. |
| """ |
| |
| try: |
| fn_hdl = io.open(_unicode_encode( |
| fn_path, encoding=_encodings['fs'], errors='strict'), |
| mode='rb') |
| except EnvironmentError: |
| return |
| |
| orig_header = [] |
| new_header = [] |
| |
| for line in fn_hdl: |
| line_strip = line.strip() |
| orig_header.append(line) |
| if not line_strip or line_strip[:1] != b'#': |
| new_header.append(line) |
| break |
| |
| line = update_copyright_year(year, line) |
| new_header.append(line) |
| |
| difflines = 0 |
| for diffline in difflib.unified_diff( |
| [_unicode_decode(diffline) for diffline in orig_header], |
| [_unicode_decode(diffline) for diffline in new_header], |
| fromfile=fn_path, tofile=fn_path, n=0): |
| util.writemsg_stdout(diffline, noiselevel=-1) |
| difflines += 1 |
| util.writemsg_stdout("\n", noiselevel=-1) |
| |
| # unified diff has three lines to start with |
| if difflines > 3 and not pretend: |
| # write new file with changed header |
| f, fnnew_path = mkstemp() |
| f = io.open(f, mode='wb') |
| for line in new_header: |
| f.write(line) |
| for line in fn_hdl: |
| f.write(line) |
| f.close() |
| try: |
| fn_stat = os.stat(fn_path) |
| except OSError: |
| fn_stat = None |
| |
| shutil.move(fnnew_path, fn_path) |
| |
| if fn_stat is None: |
| util.apply_permissions(fn_path, mode=0o644) |
| else: |
| util.apply_stat_permissions(fn_path, fn_stat) |
| fn_hdl.close() |