diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9d9474a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*~
+/testfiles
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..414cd13
--- /dev/null
+++ b/LICENSE.txt
@@ -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.
+
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..106f0c3
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,3 @@
+include LICENSE.txt
+include README.md
+
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..7b16757
--- /dev/null
+++ b/README.rst
@@ -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
+
diff --git a/license-headers.py b/license-headers.py
new file mode 100644
index 0000000..8b136db
--- /dev/null
+++ b/license-headers.py
@@ -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())
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..bcca040
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,4 @@
+[egg_info]
+tag_build =
+tag_date = 0
+tag_svn_revision = 0
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..5abe229
--- /dev/null
+++ b/setup.py
@@ -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",
+ ],
+)
diff --git a/templates/agpl-v3.tmpl b/templates/agpl-v3.tmpl
new file mode 100644
index 0000000..15b3f14
--- /dev/null
+++ b/templates/agpl-v3.tmpl
@@ -0,0 +1,17 @@
+Copyright (c) ${years} ${owner}.
+
+This file is part of ${projectname}
+(see ${projecturl}).
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
diff --git a/templates/apache-2.tmpl b/templates/apache-2.tmpl
new file mode 100644
index 0000000..631f6a0
--- /dev/null
+++ b/templates/apache-2.tmpl
@@ -0,0 +1,21 @@
+Copyright (c) ${years} ${owner}.
+
+This file is part of ${projectname}
+(see ${projecturl}).
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
diff --git a/templates/bsd-3.tmpl b/templates/bsd-3.tmpl
new file mode 100644
index 0000000..2828051
--- /dev/null
+++ b/templates/bsd-3.tmpl
@@ -0,0 +1,6 @@
+Copyright (c) ${years} ${owner}.
+
+This file is part of ${projectname}
+(see ${projecturl}).
+
+License: 3-clause BSD, see https://opensource.org/licenses/BSD-3-Clause
diff --git a/templates/gpl-v3.tmpl b/templates/gpl-v3.tmpl
new file mode 100644
index 0000000..de7d736
--- /dev/null
+++ b/templates/gpl-v3.tmpl
@@ -0,0 +1,17 @@
+Copyright (c) ${years} ${owner}.
+
+This file is part of ${projectname}
+(see ${projecturl}).
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
diff --git a/templates/lgpl-v2.1.tmpl b/templates/lgpl-v2.1.tmpl
new file mode 100644
index 0000000..572655b
--- /dev/null
+++ b/templates/lgpl-v2.1.tmpl
@@ -0,0 +1,17 @@
+Copyright (c) ${years} ${owner}.
+
+This file is part of ${projectname}
+(see ${projecturl}).
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see .
diff --git a/templates/lgpl-v3.tmpl b/templates/lgpl-v3.tmpl
new file mode 100644
index 0000000..357d105
--- /dev/null
+++ b/templates/lgpl-v3.tmpl
@@ -0,0 +1,17 @@
+Copyright (c) ${years} ${owner}.
+
+This file is part of ${projectname}
+(see ${projecturl}).
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see .