-#!/usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-
-# Copyright 2016 EDF R&D
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# Copyright (C) 2017-2024 OPEN CASCADE
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License Version 3 as
Usage: type "insert_copyright --help" to learn how to use tool.
"""
-import optparse
-import os
+import argparse
+import os.path as osp
import re
import sys
import time
-# pragma pylint: disable=redefined-builtin
-
# -----------------------------------------------------------------------------
_COMMENTS = {
- 'cpp' : '//',
- 'shell' : '#',
- 'python' : '#',
- 'auto' : None,
+ 'cpp': '//',
+ 'shell': '#',
+ 'python': '#',
+ 'auto': None,
}
_OWNERS = {
- 'cea' : 'CEA/DEN',
- 'edf' : 'EDF R&D',
- 'occ' : 'OPEN CASCADE'
+ 'cea': 'CEA/DEN',
+ 'edf': 'EDF R&D',
+ 'occ': 'OPEN CASCADE'
}
+
# -----------------------------------------------------------------------------
def error_exit(msg):
"""
sys.stderr.write("ERROR: {}\n".format(msg))
sys.exit(-1)
+
# -----------------------------------------------------------------------------
def warning(msg):
"""
"""
sys.stderr.write("WARNING: {}\n".format(msg))
+
# -----------------------------------------------------------------------------
def formats():
"""
Returns:
list[str]: List of formats.
"""
- return _COMMENTS.keys()
+ return list(_COMMENTS)
+
# -----------------------------------------------------------------------------
def search_line(lines, rex, depth=1):
return i
return -1
+
# -----------------------------------------------------------------------------
def get_owner(owner):
"""
result.append(i)
return ', '.join(result)
+
# -----------------------------------------------------------------------------
-def get_comment(format):
+def get_comment(file_format):
"""
Get comment for given format.
str: Comment signature for given format; *None* for unsupported
format.
"""
- return _COMMENTS.get(format) if format else None
+ return _COMMENTS.get(file_format) if file_format else None
+
# -----------------------------------------------------------------------------
def get_copyright(comment, owner, year):
Returns:
list[str]: List of strings with copyright data.
"""
- template = os.path.join(os.path.dirname(sys.argv[0]), 'copyright.template')
- copyright = []
+ template = osp.join(osp.dirname(sys.argv[0]), 'copyright.template')
try:
with open(template) as fid:
- copyright = fid.readlines()
+ cp_notice = [i.strip() for i in fid.readlines()]
+ cp_notice = [i % {'year' : year, 'owner' : owner} for i in cp_notice]
+ cp_notice = [comment + ' ' + i if i else comment for i in cp_notice]
+ return [i + '\n' for i in cp_notice] + ['\n']
except IOError:
error_exit("cannot find copyright template")
- copyright = [i.replace('@year@', year) for i in copyright]
- copyright = [i.replace('@owner@', owner) for i in copyright]
- copyright = [comment + ' ' + i for i in copyright]
- return copyright
+ return []
+
# -----------------------------------------------------------------------------
def get_module_owner(module):
Returns:
str: Module's owner.
"""
- modules_info = os.path.join(os.path.dirname(sys.argv[0]), 'modules.info')
+ modules_info = osp.join(osp.dirname(sys.argv[0]), 'modules.info')
owner = None
try:
with open(modules_info) as fid:
warning("cannot find modules info file")
return owner
+
# -----------------------------------------------------------------------------
def autodetect_owner(filename):
"""
Returns:
str: Owner; *None* if owner isn't detected.
"""
- filename = os.path.realpath(filename)
- if os.path.exists(filename):
- directory = os.path.dirname(filename)
+ filename = osp.realpath(filename)
+ if osp.exists(filename):
+ directory = osp.dirname(filename)
while directory != '/':
- config_file = os.path.join(directory, '.git', 'config')
- if os.path.exists(config_file):
- from ConfigParser import ConfigParser
- from StringIO import StringIO
+ config_file = osp.join(directory, '.git', 'config')
+ if osp.exists(config_file):
+ try:
+ from ConfigParser import ConfigParser
+ except ImportError:
+ from configparser import ConfigParser
+ try:
+ from StringIO import StringIO
+ except ImportError:
+ from io import StringIO
with open(config_file) as fid:
gitcfg = fid.readlines()
cfg = ConfigParser()
data = StringIO(''.join([l.lstrip() for l in gitcfg]))
- cfg.readfp(data)
+ cfg.readfp(data) # pragma pylint: disable=deprecated-method
url = cfg.get('remote "origin"', 'url')
- module = os.path.split(url)[-1]
+ module = osp.split(url)[-1]
if module.endswith('.git'):
module = module[:-4]
return get_module_owner(module)
break
- directory = os.path.dirname(directory)
+ directory = osp.dirname(directory)
return None
+
# -----------------------------------------------------------------------------
def autodetect_format(filename):
"""
str: Format of comments; *None* if format isn't detected.
"""
extensions = {
- 'cpp' : ('c', 'cpp', 'cxx', 'cc', 'c++',
- 'h', 'hxx', 'hpp', 'hh', 'h++',
- 'idl', 'i'),
- 'shell' : ('sh', 'bash', 'csh', 'cmake', 'txt', 'cfg', 'ini', 'm4'),
- 'python' : ('py',),
+ 'cpp': ('c', 'cpp', 'cxx', 'cc', 'c++',
+ 'h', 'hxx', 'hpp', 'hh', 'h++',
+ 'idl', 'i'),
+ 'shell': ('sh', 'bash', 'csh', 'cmake', 'txt', 'cfg', 'ini', 'm4'),
+ 'python': ('py',),
}
- if filename and os.path.isfile(filename):
- extension = os.path.splitext(filename)[1][1:].lower()
+ rev_extensions = {e: k for k, exts in extensions.items() for e in exts}
+ if filename and osp.isfile(filename):
+ extension = osp.splitext(filename)[1][1:].lower()
if extension in ('in',):
- name = os.path.splitext(filename)[0]
- extension = os.path.splitext(name)[1][1:].lower()
- for format in extensions:
- if extension in extensions[format]:
- return format
+ name = osp.splitext(filename)[0]
+ extension = osp.splitext(name)[1][1:].lower()
+ if extension in rev_extensions:
+ return rev_extensions[extension]
+
+ try:
+ import magic
+ mtool = magic.open(magic.MAGIC_MIME_TYPE)
+ mtool.load()
+ file_formats = {
+ 'cpp': ('text/x-c', 'text/x-c++'),
+ 'shell': ('text/x-shellscript',),
+ 'python': ('text/x-python',),
+ }
+ rev_file_formats = {f: k for k, ff in file_formats.items() for f in ff}
+ file_format = mtool.file(filename)
+ if file_format in rev_file_formats:
+ return rev_file_formats[file_format]
+ except ImportError:
+ pass
+
return None
+
# -----------------------------------------------------------------------------
-def insert_copyright(filename, owner, year, format):
+def insert_copyright(filename, owner, year, file_format):
"""
Insert copyright note to a file.
filename (str): File path.
owner (str): Copyright owner.
year (str): Copyright year(s).
- format (str): Format of comments.
+ file_format (str): Format of comments.
"""
try:
with open(filename) as fid:
warning("cannot read file: {}".format(filename))
return
- if format in ('auto',):
- format = autodetect_format(filename)
+ if file_format in ('auto',):
+ file_format = autodetect_format(filename)
if owner.lower() in ('auto',):
owner = autodetect_owner(filename) or get_owner('all')
else:
owner = get_owner(owner)
- comment = get_comment(format)
+ comment = get_comment(file_format)
if comment is None:
warning("cannot detect format")
return
shell_row = search_line(lines, r'^#!') \
- if format in ('sh', 'bash', 'csh', 'py', 'python') else -1
- coding_row = search_line(lines, r'-\*- coding:', 3) \
- if format in ('py', 'python') else -1
- insert_point = max(0, shell_row+1, coding_row+1)
-
- copyright = get_copyright(comment, owner, year)
- if copyright:
- lines = lines[:insert_point] + copyright + ['\n'] \
- + lines[insert_point:]
+ if file_format in ('sh', 'bash', 'csh', 'py', 'python') else -1
+ coding_row = search_line(lines, r'coding:', 3) \
+ if file_format in ('py', 'python') else -1
+ insert_point = max(0, shell_row + 1, coding_row + 1)
+
+ cp_notice = get_copyright(comment, owner, year)
+ if cp_notice:
+ lines[insert_point:insert_point] = cp_notice
try:
with open(filename, 'w') as fid:
for line in lines:
warning("cannot write file: {}".format(filename))
return
+
# -----------------------------------------------------------------------------
def main():
"""Main function."""
# Parse command line.
- usage = "%prog [options] [FILE] ..."
- description = "Command line tool to insert copyright notice to a file."
- parser = optparse.OptionParser(usage=usage, description=description)
+ description = "Command line tool to insert copyright notice to file(s)."
+ parser = argparse.ArgumentParser(description=description)
help_string = "copyright owner; if not specified, tool tries to " \
"autodetect an owner from the file path; if auto-detection fails, " \
"an owner is set to '{owner}'"
owner = 'auto'
- parser.add_option("-o", "--owner", action="store",
- dest="owner", default=owner,
- help=help_string.format(owner=get_owner('all')))
+ parser.add_argument("-o", "--owner", action="store",
+ dest="owner", default=owner,
+ help=help_string.format(owner=get_owner('all')))
help_string = "copyright year(s); default: current year ({year})"
year = str(time.localtime().tm_year)
- parser.add_option("-y", "--year", action="store",
- dest="year", default=year,
- help=help_string.format(year=year))
- help_string = "format of comments ({choices}); default: {format}"
- format = 'auto'
- parser.add_option("-f", "--format", action="store",
- type='choice', choices=formats(),
- dest="format", default=format,
- help=help_string.format(format=format,
- choices="|".join(formats())))
-
- options, files = parser.parse_args(sys.argv[1:])
-
- owner = options.owner
- year = options.year
- format = options.format
-
- if not files:
- error_exit('file is not specified')
+ parser.add_argument("-y", "--year", action="store",
+ dest="year", default=year,
+ help=help_string.format(year=year))
+ help_string = "format of comments ({choices}); default: {file_format}"
+ file_format = 'auto'
+ parser.add_argument("-f", "--format", action="store", choices=formats(),
+ dest="format", default=file_format,
+ help=help_string.format(file_format=file_format,
+ choices="|".join(formats())))
+ help_string = "file where to insert copyright notice"
+ parser.add_argument('files', nargs='+', metavar='FILE', help=help_string)
+
+ args = parser.parse_args(sys.argv[1:])
+
+ owner = args.owner
+ year = args.year
+ file_format = args.format
+ files = args.files
for filename in files:
- insert_copyright(filename, owner, year, format)
+ insert_copyright(filename, owner, year, file_format)
return 0