blob: 275dcbc3fdb0933a821b77a207e7d32c62665aad [file] [log] [blame]
# -*- 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( Gentoo (Foundation|Authors))\b')
_copyright_re2 = \
re.compile(br'^(# Copyright )(\d\d\d\d)( Gentoo (Foundation|Authors))\b')
class _copyright_repl(object):
__slots__ = ('year',)
def __init__(self, year):
self.year = year
def __call__(self, matchobj):
if == self.year:
return + + \
b'-' + self.year + b' Gentoo Authors'
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
if not line.startswith('# Copyright '):
return line
year = _unicode_encode(year)
line = _unicode_encode(line)
line = _copyright_re1.sub(br'\1-' + year + b' Gentoo Authors', 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.
@param fn_path: file path
@type str
@param year: current year
@type str
@param pretend: pretend mode
@type bool
@rtype: bool
@return: True if copyright update was needed, False otherwise
fn_hdl =
fn_path, encoding=_encodings['fs'], errors='strict'),
except EnvironmentError:
orig_header = []
new_header = []
for line in fn_hdl:
line_strip = line.strip()
if not line_strip or line_strip[:1] != b'#':
line = update_copyright_year(year, 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 =, mode='wb')
for line in new_header:
for line in fn_hdl:
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)
util.apply_stat_permissions(fn_path, fn_stat)
return difflines > 3