git subrepo pull (merge) --force deps/libchdr
[pcsx_rearmed.git] / deps / libchdr / deps / zstd-1.5.5 / tests / test-license.py
1 #!/usr/bin/env python3
2
3 # ################################################################
4 # Copyright (c) Meta Platforms, Inc. and affiliates.
5 # All rights reserved.
6 #
7 # This source code is licensed under both the BSD-style license (found in the
8 # LICENSE file in the root directory of this source tree) and the GPLv2 (found
9 # in the COPYING file in the root directory of this source tree).
10 # You may select, at your option, one of the above-listed licenses.
11 # ################################################################
12
13 import enum
14 import glob
15 import os
16 import re
17 import sys
18
19 ROOT = os.path.join(os.path.dirname(__file__), "..")
20
21 RELDIRS = [
22     "doc",
23     "examples",
24     "lib",
25     "programs",
26     "tests",
27     "contrib/linux-kernel",
28 ]
29
30 REL_EXCLUDES = [
31     "contrib/linux-kernel/test/include",
32 ]
33
34 def to_abs(d):
35     return os.path.normpath(os.path.join(ROOT, d)) + "/"
36
37 DIRS = [to_abs(d) for d in RELDIRS]
38 EXCLUDES = [to_abs(d) for d in REL_EXCLUDES]
39
40 SUFFIXES = [
41     ".c",
42     ".h",
43     "Makefile",
44     ".mk",
45     ".py",
46     ".S",
47 ]
48
49 # License should certainly be in the first 10 KB.
50 MAX_BYTES = 10000
51 MAX_LINES = 50
52
53 LICENSE_LINES = [
54     "This source code is licensed under both the BSD-style license (found in the",
55     "LICENSE file in the root directory of this source tree) and the GPLv2 (found",
56     "in the COPYING file in the root directory of this source tree).",
57     "You may select, at your option, one of the above-listed licenses.",
58 ]
59
60 COPYRIGHT_EXCEPTIONS = {
61     # From zstdmt
62     "threading.c",
63     "threading.h",
64     # From divsufsort
65     "divsufsort.c",
66     "divsufsort.h",
67 }
68
69 LICENSE_EXCEPTIONS = {
70     # From divsufsort
71     "divsufsort.c",
72     "divsufsort.h",
73     # License is slightly different because it references GitHub
74     "linux_zstd.h",
75 }
76
77
78 def valid_copyright(lines):
79     YEAR_REGEX = re.compile("\d\d\d\d|present")
80     for line in lines:
81         line = line.strip()
82         if "Copyright" not in line:
83             continue
84         if "present" in line:
85             return (False, f"Copyright line '{line}' contains 'present'!")
86         if "Meta Platforms, Inc" not in line:
87             return (False, f"Copyright line '{line}' does not contain 'Meta Platforms, Inc'")
88         year = YEAR_REGEX.search(line)
89         if year is not None:
90             return (False, f"Copyright line '{line}' contains {year.group(0)}; it should be yearless")
91         if " (c) " not in line:
92             return (False, f"Copyright line '{line}' does not contain ' (c) '!")
93         return (True, "")
94     return (False, "Copyright not found!")
95
96
97 def valid_license(lines):
98     for b in range(len(lines)):
99         if LICENSE_LINES[0] not in lines[b]:
100             continue
101         for l in range(len(LICENSE_LINES)):
102             if LICENSE_LINES[l] not in lines[b + l]:
103                 message = f"""Invalid license line found starting on line {b + l}!
104 Expected: '{LICENSE_LINES[l]}'
105 Actual: '{lines[b + l]}'"""
106                 return (False, message)
107         return (True, "")
108     return (False, "License not found!")
109
110
111 def valid_file(filename):
112     with open(filename, "r") as f:
113         lines = f.readlines(MAX_BYTES)
114     lines = lines[:min(len(lines), MAX_LINES)]
115
116     ok = True
117     if os.path.basename(filename) not in COPYRIGHT_EXCEPTIONS:
118         c_ok, c_msg = valid_copyright(lines)
119         if not c_ok:
120             print(f"{filename}: {c_msg}", file=sys.stderr)
121             ok = False
122     if os.path.basename(filename) not in LICENSE_EXCEPTIONS:
123         l_ok, l_msg = valid_license(lines)
124         if not l_ok:
125             print(f"{filename}: {l_msg}", file=sys.stderr)
126             ok = False
127     return ok
128
129
130 def exclude(filename):
131     for x in EXCLUDES:
132         if filename.startswith(x):
133             return True
134     return False
135
136 def main():
137     invalid_files = []
138     for directory in DIRS:
139         for suffix in SUFFIXES:
140             files = set(glob.glob(f"{directory}/**/*{suffix}", recursive=True))
141             for filename in files:
142                 if exclude(filename):
143                     continue
144                 if not valid_file(filename):
145                     invalid_files.append(filename)
146     if len(invalid_files) > 0:
147         print("Fail!", file=sys.stderr)
148         for f in invalid_files:
149             print(f)
150         return 1
151     else:
152         print("Pass!", file=sys.stderr)
153         return 0
154
155 if __name__ == "__main__":
156     sys.exit(main())