188 lines
5.1 KiB
Python
Executable File
188 lines
5.1 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
# SPDX-FileCopyrightText: 2023 The LineageOS Project
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
# REUSE-IgnoreStart
|
|
import argparse
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
from pathlib import Path
|
|
from utils import check_dependencies, run_subprocess
|
|
|
|
|
|
def fix_files(project_path, extension, args):
|
|
extension_map = {
|
|
"*.java": ["java"],
|
|
"*.bp": ["java", "c"],
|
|
"*.proto": ["java", "c"],
|
|
"*.xml": ["xml"],
|
|
"*.py": ["py"],
|
|
}
|
|
path_list = Path(project_path).rglob(extension)
|
|
for item in path_list:
|
|
path_in_str = str(item)
|
|
if extension in extension_map:
|
|
for comment_style in extension_map[extension]:
|
|
clean_file(path_in_str, comment_style, args)
|
|
return
|
|
|
|
|
|
def clean_file(file, comment_style, args):
|
|
if should_ignore_file(file):
|
|
return
|
|
|
|
try:
|
|
fh = open(file, "r+")
|
|
except OSError:
|
|
print(f"Something went wrong while opening file {file}")
|
|
return
|
|
|
|
content = fh.read()
|
|
|
|
pattern_map = {
|
|
"c": r"((//[^\n]*\n)*(//)?)",
|
|
"java": r"(/\*.*?\*/)",
|
|
"py": r"((#[^\n]*\n)*#?)",
|
|
"xml": r"(<!--.*?-->)",
|
|
}
|
|
if comment_style not in pattern_map:
|
|
print(f"Comment style '{comment_style}' unsupported!")
|
|
return
|
|
pattern = pattern_map[comment_style]
|
|
match = re.search(pattern, content, re.DOTALL)
|
|
if match is None:
|
|
fh.close()
|
|
return
|
|
|
|
comment = match.group(1)
|
|
license_type = get_license_type(comment)
|
|
parts = comment.split("\n")
|
|
if len(parts) == 1:
|
|
fh.close()
|
|
return
|
|
|
|
i = 0
|
|
match = None
|
|
while match is None:
|
|
if len(parts) <= i:
|
|
break
|
|
match = re.search(r".*Copyright (?:\([cC]\))?\s*(.*)", parts[i])
|
|
if not match:
|
|
i += 1
|
|
|
|
if match is None:
|
|
fh.close()
|
|
return
|
|
|
|
copyright_lines = [match.group(1)]
|
|
pattern = re.compile(r"\s*\*?\s+(?:(?:Copyright )?\([Cc]\))?\s*((\d+)(.*))")
|
|
match = pattern.match(parts[i + 1])
|
|
while match is not None:
|
|
copyright_lines.append(match.group(1))
|
|
i += 1
|
|
match = pattern.match(parts[i + 1])
|
|
|
|
if license_type is not None:
|
|
new_comment = build_spdx_comment(comment_style, copyright_lines, license_type)
|
|
new_content = content.replace(comment, new_comment)
|
|
if args.fix_newlines:
|
|
if new_content[-1] != "\n":
|
|
new_content += "\n"
|
|
fh.seek(0)
|
|
fh.write(new_content)
|
|
fh.truncate()
|
|
fh.close()
|
|
|
|
|
|
def should_ignore_file(file):
|
|
if not "/res/values-" in file:
|
|
return False
|
|
else:
|
|
# We want to ignore translations
|
|
can_modify_values = ["land", "large", "night", "television", "v2", "v3"]
|
|
for m in can_modify_values:
|
|
if re.search(rf"/values-{m}", file):
|
|
return False
|
|
return True
|
|
|
|
|
|
def build_spdx_comment(comment_style, copyright_lines, license_type):
|
|
if comment_style == "java" or comment_style == "c":
|
|
return build_comment(copyright_lines, license_type, "/*\n", " * ", " */")
|
|
elif comment_style == "xml":
|
|
return build_comment(copyright_lines, license_type, "<!--\n", " ", "-->")
|
|
elif comment_style == "py":
|
|
return build_comment(copyright_lines, license_type, "", "# ", "")
|
|
else:
|
|
return ""
|
|
|
|
|
|
def build_comment(copyright_lines, license_type, comment_start, comment_middle, comment_end):
|
|
comment = comment_start
|
|
for line in copyright_lines:
|
|
comment += f"{comment_middle}SPDX-FileCopyrightText: {line}\n"
|
|
comment += f"{comment_middle}SPDX-License-Identifier: {license_type}\n"
|
|
comment += comment_end
|
|
return comment
|
|
|
|
|
|
def get_license_type(comment):
|
|
lic = None
|
|
if "http://www.apache.org/licenses/LICENSE-2.0" in comment:
|
|
lic = "Apache-2.0"
|
|
elif "GNU General Public" in comment and "version 2" in comment:
|
|
lic = "GPL-2.0-or-later"
|
|
|
|
return lic
|
|
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser(description="Make project REUSE compliant")
|
|
parser.add_argument(
|
|
"-r", "--root", default=None, help="Specify the root path of your sources"
|
|
)
|
|
parser.add_argument(
|
|
"-p",
|
|
"--project",
|
|
required=True,
|
|
help="Specify the relative path of the project you want to convert",
|
|
)
|
|
parser.add_argument(
|
|
"-f",
|
|
"--fix_newlines",
|
|
action="store_true",
|
|
help="Add newlines to files that miss them",
|
|
)
|
|
return parser.parse_args()
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
root = args.root
|
|
if args.root is None:
|
|
root = str(Path.cwd())
|
|
root = root.replace("/lineage/scripts/reuse_helper", "")
|
|
|
|
path = os.path.join(root, args.project)
|
|
|
|
# We need "pipx"
|
|
if not check_dependencies():
|
|
sys.exit(-1)
|
|
|
|
# Parse and change known file-/comment-types
|
|
extensions = ["java", "xml", "bp", "proto", "py"]
|
|
for ext in extensions:
|
|
fix_files(path, f"*.{ext}", args)
|
|
|
|
# Download all licenses automatically
|
|
os.chdir(path)
|
|
_, code = run_subprocess(["pipx", "run", "reuse", "download", "--all"], True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
# REUSE-IgnoreEnd
|