Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit b59b633
Showing
13 changed files
with
487 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*~ | ||
/testfiles |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
:: | ||
|
||
Copyright (c) 2016 Johann Petrak | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
include LICENSE.txt | ||
include README.md | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
.. image:: https://img.shields.io/pypi/v/license-headers.svg | ||
:target: https://pypi.python.org/pypi/license-headers/ | ||
:alt: PyPi version | ||
|
||
.. image:: https://img.shields.io/pypi/pyversions/license-headers.svg | ||
:target: https://pypi.python.org/pypi/license-headers/ | ||
:alt: Python compatibility | ||
|
||
.. image:: https://img.shields.io/travis/elmotec/license-headers.svg | ||
:target: https://travis-ci.org/elmotec/license-headers | ||
:alt: Build Status | ||
|
||
.. image:: https://img.shields.io/pypi/dm/license-headers.svg | ||
:alt: PyPi | ||
:target: https://pypi.python.org/pypi/license-headers | ||
|
||
.. image:: https://coveralls.io/repos/elmotec/license-headers/badge.svg | ||
:target: https://coveralls.io/r/elmotec/license-headers | ||
:alt: Coverage | ||
|
||
.. image:: https://img.shields.io/codacy/474b0af6853a4c5f8f9214d3220571f9.svg | ||
:target: https://www.codacy.com/app/elmotec/license-headers/dashboard | ||
:alt: Codacy | ||
|
||
|
||
======== | ||
license-headers | ||
======== | ||
|
||
A tool to update, change or add license headers to all files of any of | ||
the supported types in or below some directory. | ||
|
||
Currently, the following file types are supported: Java/Scala/Groovy, bash/sh/csh, ... | ||
|
||
|
||
Usage | ||
----- | ||
|
||
:: | ||
|
||
usage: license-headers.py [-h] [-v] [-V] [-d directory] [-t template] [-y years] [-b] [-a] | ||
[-c copyrightOwner] | ||
|
||
License Header Updater | ||
|
||
positional arguments: none | ||
|
||
optional arguments: | ||
-h, --help show this help message and exit | ||
-V, --version show program's version number and exit | ||
-v, --verbose increases log verbosity (can be specified multiple times) | ||
-d, --dir directory to process, all subdirectories will be included | ||
-t, --tmpl template name or file to use (if not specified, -y must be specified) | ||
-y, --years if template is specified, the year to substitute, otherwise this year | ||
or year range will replace any existing year in existing headers. | ||
Replaces variable ${years} in a template | ||
-b, --backup for each file that gets changed, create a backup of the original with | ||
the additional filename extension .bak | ||
-c, --cr copyright owner, replaces variable ${owner} in a template | ||
-a, --addonly add a header to all supported file types, ignore any existing headers. | ||
|
||
Examples: | ||
# Add a new license header or replace any existing one based on the lgpl3 template. | ||
# Process all files of supported type in or below the current directory. | ||
# Use "Eager Hacker" as the copyright owner. | ||
license-headers.py -t lgpl3 -c "Eager Hacker" | ||
|
||
|
||
If license-headers is installed as a package (from pypi for instance), one can interact with it as a command line tool: | ||
|
||
:: | ||
|
||
python -m license-headers -t lgpl3 -c "Eager Hacker" | ||
|
||
|
||
Installation | ||
------------ | ||
|
||
Download ``license-headers.py`` from ``http://github.com/johann-petrak/license-headers`` or : | ||
|
||
:: | ||
|
||
pip install license-headers | ||
|
||
|
||
Template names and files | ||
------------------------ | ||
|
||
This library comes with a number of predefined templates. If a template name is specified | ||
which when matched against all predefined template names matches exactly one as a substring, | ||
then that template is used. Otherwise the name is expected to be the path of file. | ||
|
||
If a template does not contain any variables of the form `${varname}` it is used as is. | ||
Otherwise the program will try to replace the variable from one of the following | ||
sources: | ||
|
||
- an environment variable with the same name but the prefix `LICENSE_HEADERS_` added | ||
- the command line option that can be used to set the variable (see usage) | ||
|
||
|
||
Supported file types and how they are processed | ||
----------------------------------------------- | ||
|
||
Java: | ||
- assumed for all files with the extensions: .java, .scala, .groovy | ||
- only headers that use Java block comments are recognised as existing headers | ||
- the template text will be wrapped in block comments | ||
|
||
License | ||
------- | ||
|
||
Licensed under the term of `MIT License`_. See attached file LICENSE.txt. | ||
|
||
|
||
.. _MIT License: http://en.wikipedia.org/wiki/MIT_License | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
#!/usr/bin/env python | ||
# encoding: utf-8 | ||
|
||
"""A tool to change or add license headers in all supported files in or below a directory.""" | ||
|
||
# Copyright (c) 2016 Johann Petrak | ||
# | ||
# Permission is hereby granted, free of charge, to any person obtaining a copy | ||
# of this software and associated documentation files (the "Software"), to deal | ||
# in the Software without restriction, including without limitation the rights | ||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
# copies of the Software, and to permit persons to whom the Software is | ||
# furnished to do so, subject to the following conditions: | ||
# | ||
# The above copyright notice and this permission notice shall be included in | ||
# all copies or substantial portions of the Software. | ||
# | ||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
# THE SOFTWARE. | ||
|
||
from __future__ import unicode_literals | ||
from __future__ import print_function | ||
|
||
|
||
import os | ||
import shutil | ||
import sys | ||
import logging | ||
import argparse | ||
import re | ||
import fnmatch | ||
from string import Template | ||
import io | ||
import subprocess | ||
|
||
|
||
__version__ = '0.1' | ||
__author__ = 'Johann Petrak' | ||
__license__ = 'MIT' | ||
|
||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
try: | ||
unicode | ||
except NameError: | ||
unicode = str | ||
|
||
|
||
## all filename pattherns of files we know how to process | ||
patterns = ["*.java","*.scala","*.groovy","*.jape"] | ||
|
||
## how each file extension maps to a specific processing type | ||
processingTypes = { | ||
"java": "java", | ||
"scala": "java", | ||
"groovy": "java", | ||
"jape": "java" | ||
} | ||
|
||
## for each processing type, the detailed settings of how to process files of that type | ||
typeSettings = { | ||
"java": { | ||
"headerStartPattern": "/*", ## used to find the beginning of a header bloc | ||
"headerEndPattern": "*/", ## used to find the end of a header block | ||
"headerStartLine": "/*\n", ## inserted before the first header text line | ||
"headerEndLine": " */\n", ## inserted after the last header text line | ||
"linePrefix": " * ", ## inserted before each header text line | ||
"lineSuffix": "", ## inserted after each header text line, but before the new line | ||
} | ||
} | ||
|
||
def parse_command_line(argv): | ||
"""Parse command line argument. See -h option. | ||
Arguments: | ||
argv: arguments on the command line must include caller file name. | ||
""" | ||
import textwrap | ||
|
||
example = textwrap.dedent(""" | ||
## Some examples of how to use this command! | ||
""").format(os.path.basename(argv[0])) | ||
formatter_class = argparse.RawDescriptionHelpFormatter | ||
parser = argparse.ArgumentParser(description="Python license header updater", | ||
epilog=example, | ||
formatter_class=formatter_class) | ||
parser.add_argument("-V", "--version", action="version", | ||
version="%(prog)s {}".format(__version__)) | ||
parser.add_argument("-v", "--verbose", dest="verbose_count", | ||
action="count", default=0, | ||
help="increases log verbosity (can be specified " | ||
"multiple times)") | ||
parser.add_argument("-d", "--dir", dest="dir", nargs=1, | ||
help="The directory to recursively process.") | ||
parser.add_argument("-t", "--tmpl", dest="tmpl", nargs=1, | ||
help="Template name or file to use.") | ||
parser.add_argument("-y", "--years", dest="years", nargs=1, | ||
help="Year or year range to use.") | ||
parser.add_argument("-o", "--owner", dest="owner", nargs=1, | ||
help="Name of copyright owner to use.") | ||
parser.add_argument("-n", "--projname", dest="projectname", nargs=1, | ||
help="Name of project to use.") | ||
parser.add_argument("-u", "--projurl", dest="projecturl", nargs=1, | ||
help="Url of project to use.") | ||
arguments = parser.parse_args(argv[1:]) | ||
|
||
# Sets log level to WARN going more verbose for each new -V. | ||
log.setLevel(max(3 - arguments.verbose_count, 0) * 10) | ||
return arguments | ||
|
||
|
||
def get_paths(patterns, start_dir="."): | ||
"""Retrieve files that match any of the glob patterns from the start_dir and below.""" | ||
for root, dirs, files in os.walk(start_dir): | ||
names = [] | ||
for pattern in patterns: | ||
names += fnmatch.filter(files, pattern) | ||
for name in names: | ||
path = os.path.join(root, name) | ||
yield path | ||
|
||
## return an array of lines, with all the variables replaced | ||
## throws an error if a variable cannot be replaced | ||
def read_template(templateFile,dict): | ||
with open(templateFile,'r') as f: | ||
lines = f.readlines() | ||
lines = [Template(line).substitute(dict) for line in lines] ## use safe_substitute if we do not want an error | ||
return lines | ||
|
||
def main(): | ||
"""Main function.""" | ||
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG) | ||
try: | ||
error = False | ||
settings = { | ||
} | ||
templateLines = None | ||
arguments = parse_command_line(sys.argv) | ||
if arguments.dir: | ||
start_dir = arguments.dir[0] | ||
else: | ||
start_dir = "." | ||
if arguments.years: | ||
settings["years"] = arguments.years[0] | ||
if arguments.owner: | ||
settings["owner"] = arguments.owner[0] | ||
if arguments.projectname: | ||
settings["projectname"] = arguments.projectname[0] | ||
if arguments.projecturl: | ||
settings["projecturl"] = arguments.projecturl[0] | ||
## if we have a template name specified, try to get or load the template | ||
if arguments.tmpl: | ||
opt_tmpl = arguments.tmpl[0] | ||
## first get all the names of our own templates | ||
## for this get first the path of this file | ||
templatesDir = os.path.join(os.path.dirname(os.path.abspath(__file__)),"templates") | ||
## get all the templates in the templates directory | ||
templates = [f for f in get_paths("*.tmpl",templatesDir)] | ||
templates = [(os.path.splitext(os.path.basename(t))[0],t) for t in templates] | ||
## filter by trying to match the name against what was specified | ||
tmpls = [t for t in templates if opt_tmpl in t[0]] | ||
if len(tmpls) == 1: | ||
tmplName = tmpls[0][0] | ||
tmplFile = tmpls[0][1] | ||
print("Using template ",tmplName) | ||
templateLines = read_template(tmplFile,settings) | ||
else: | ||
if len(tmpls) == 0: | ||
## check if we can interpret the option as file | ||
if os.path.isfile(opt_tmpl): | ||
print("Using file ",os.path.abspath(opt_tmpl)) | ||
templateLines = read_template(os.path.abspath(opt_tmpl),settings) | ||
else: | ||
print("Not a built-in template and not a file, cannot proceed: ",opt_tmpl) | ||
error = True | ||
else: | ||
## notify that there are multiple matching templates | ||
print("There are multiple matching template names: ",[t[0] for t in tmpls]) | ||
error = True | ||
else: # no tmpl parameter | ||
if not arguments.years: | ||
print("No template specified and no years either, nothing to do") | ||
error = True | ||
if not error: | ||
logging.debug("Got template lines: ",templateLines) | ||
## now do the actual processing: if we did not get some error, we have a template loaded or no template at all | ||
## if we have no template, then we will have the years. | ||
## now process all the files and either replace the years or replace/add the header | ||
print("Processing directory ",start_dir) | ||
for file in get_paths(patterns,start_dir): | ||
print("Processing file: ",file) | ||
## | ||
finally: | ||
logging.shutdown() | ||
|
||
|
||
if __name__ == "__main__": | ||
sys.exit(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
[egg_info] | ||
tag_build = | ||
tag_date = 0 | ||
tag_svn_revision = 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#!/usr/bin/env python | ||
# encoding: utf-8 | ||
|
||
"""Packaging script.""" | ||
|
||
import os | ||
from setuptools import setup | ||
|
||
here = os.path.abspath(os.path.dirname(__file__)) | ||
readme = open(os.path.join(here, 'README.rst')).read() | ||
|
||
setup( | ||
name="license-headers", | ||
version="0.1", | ||
author="Johann Petrak", | ||
author_email="johann.petrak@gmail.com", | ||
description='Add or change license headers for all files in a directory', | ||
license="MIT", | ||
keywords="", | ||
url="http://github.com/johann-petrak/license-headers", | ||
py_modules=['license-headers'], | ||
entry_points={'console_scripts': ['license-headers=license-headers:main']}, | ||
long_description=readme, | ||
# test_suite='tests', | ||
setup_requires=[], | ||
# tests_require=['mock'], | ||
classifiers=["Development Status :: 5 - Production/Stable", | ||
"License :: OSI Approved :: MIT License", | ||
"Environment :: Console", | ||
"Natural Language :: English", | ||
"Programming Language :: Python :: 2.7", | ||
"Programming Language :: Python :: 3.3", | ||
"Programming Language :: Python :: 3.4", | ||
"Programming Language :: Python :: 3.5", | ||
"Topic :: Software Development", | ||
"Topic :: Software Development :: Code Generators", | ||
"Intended Audience :: Developers", | ||
], | ||
) |
Oops, something went wrong.