Skip to content

Instantly share code, notes, and snippets.

@gabrielfeo
Last active March 29, 2022 21:20
Show Gist options
  • Save gabrielfeo/7bc26bfdd4d4679a3e74962f4958bfec to your computer and use it in GitHub Desktop.
Save gabrielfeo/7bc26bfdd4d4679a3e74962f4958bfec to your computer and use it in GitHub Desktop.
Add the Mozilla Public License (MPL) v2.0 header to every source file in a directory. Apache's license-eye does this already, but its formatting of comments isn't perfect, e.g. no newline after the header comment.
#!/usr/bin/env python3
from collections import namedtuple
from ctypes import Union
import os
import argparse
from fileinput import FileInput
import textwrap
parser = argparse.ArgumentParser()
parser.add_argument("--holder", required=True)
parser.add_argument("--year", required=True)
parser.add_argument("dir")
args = parser.parse_args()
excluded_dirnames = [
'build',
]
Header = namedtuple('Header', ['comment', 'file_extensions'])
# DISCLAIMER: These are standard Exhibit A headers, but with https URLs
headers = [
Header(
comment=
f"""\
# Copyright (c) {args.year} {args.holder}
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.\
""",
file_extensions=[
'py',
'yaml',
'yml',
'sh',
'Dockerfile',
],
),
Header(
comment=
f"""\
/*
* Copyright (c) {args.year} {args.holder}
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/\
""",
file_extensions=[
'java',
'kt',
'kts',
'gradle',
'groovy',
'gvy',
],
),
]
def prepend_comment(comment, filepath):
# Trim common indents in multi-line string
comment = textwrap.dedent(comment)
if os.stat(filepath).st_size == 0:
with open(filepath, 'w') as file:
file.write(f"{comment}\n")
return
with FileInput(filepath, inplace=True) as file:
header_line = 1
for line in file:
if file.lineno() == header_line:
# Always scan line before deciding to print comment
if line.startswith("#!"):
# Print shebang and leave comment for the next round
print(line)
header_line = 2
continue
else:
print(comment)
if not line.startswith('\n'):
# Ensure there's 1 blank line between comment and first source line
print('')
print(line, end='')
def decide_header_comment(filename: str) -> str:
if filename in __file__:
# In case this script is editing its own directory
return None
file_extension = filename.split('.')[-1]
for header in headers:
if file_extension in header.file_extensions:
return header.comment
return None
for root, dirnames, filenames in os.walk(args.dir):
for exclude in [d for d in dirnames if d in excluded_dirnames]:
dirnames.remove(exclude)
for name in filenames:
comment = decide_header_comment(name)
if comment is None:
continue
path = os.path.join(root, name)
print("Editing", path)
prepend_comment(comment, path)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment