#!/usr/bin/env python3 """Builds licenses.txt (every text, as the author shipped them) and LICENSE.txt (credits of each folder once + each full license text once) for a dtsudo game. usage: licenses.py has apache-2.0.txt (Bridge.NET) and, for the chess games, the chess.js and Stockfish texts.""" import os, re, sys slug, dist, extra, out_full, out_compact = sys.argv[1:6] GAME_LICENSE = { # repository license file in the dist root } def rd(p): return open(p, encoding='utf-8', errors='replace', newline='').read().replace('\r\n', '\n') def classify(body): b = body if 'AFFERO' in b: return 'GNU Affero General Public License, version 3' if 'Version 3, 29 June 2007' in b: return 'GNU General Public License, version 3' if 'Version 2, June 1991' in b: return 'GNU General Public License, version 2' if 'Attribution-ShareAlike 4.0 International Public License' in b: return 'Creative Commons Attribution-ShareAlike 4.0 International Public License' if re.search(r'Attribution 4\.0 International', b): return 'Creative Commons Attribution 4.0 International Public License' if 'THE WORK (AS DEFINED BELOW)' in b and 'ShareAlike' in b: return 'Creative Commons Attribution-ShareAlike 3.0 Unported Public License' if 'THE WORK (AS DEFINED BELOW)' in b: return 'Creative Commons Attribution 3.0 Unported Public License' if 'Attribution 3.0 Unported' in b: return 'Creative Commons Attribution 3.0 Unported Public License' if 'SIL OPEN FONT LICENSE' in b: return 'SIL Open Font License, version 1.1' return None files = [] for dp, dn, fn in os.walk(dist): dn.sort() for f in sorted(fn): if f.lower() in ('license.txt', 'licence.txt') or f == 'MIT license.txt': files.append(os.path.join(dp, f)) files.sort(key=lambda p: (os.path.relpath(p, dist).count('/') > 0, os.path.relpath(p, dist))) full, compact, texts, seen = [], [], [], set() for p in files: rel = os.path.relpath(p, dist) t = rd(p) full.append(f"==== {rel}\n{t}\n") m = re.search(r'^\s*[-=]{20,}\s*$', t, re.M) head = t[:m.start()] if m else t body = t[m.end():] if m else '' cls = classify(body) if m else classify(t) if len(t) > 8000 else None if rel == 'LICENSE.txt' and not m: # texto do repositorio (so a licenca): vira o texto completo da classe cls = classify(t) head = '' if cls else t compact.append(f"==== {rel}\n{head.strip()}\n" if head.strip() else f"==== {rel} (license text below)\n") if cls and cls not in seen: seen.add(cls) texts.append((cls, (body if m else t).strip('\n'))) for name, label in (('bridge.js', 'Bridge.NET 17.6.0 (compiles the C# code to JavaScript; its runtime, bridge.js, goes into the game), Copyright 2008-2018 Object.NET, Inc., Apache License 2.0'),): if os.path.exists(os.path.join(dist, name)): t = rd(os.path.join(extra, 'apache-2.0.txt')) full.append(f"==== {label}\n{t}\n") compact.append(f"==== {label}\n(Apache License 2.0: full text below)\n") texts.append(('Apache License, version 2.0', t.strip('\n'))) for name, label in (('chess-js-license.txt', 'chess.js (ChessJs/chess.js), BSD 2-clause license: the notice is at the top of the file, copied here'), ('stockfish-notice.txt', 'Stockfish.js 17.1 (Stockfish/*.js, *.wasm)')): pe = os.path.join(extra, name) if os.path.exists(pe) and os.path.exists(os.path.join(dist, 'Stockfish' if 'stockfish' in name else 'ChessJs')): t = rd(pe) full.append(f"==== {label}\n{t}\n") compact.append(f"==== {label}\n{t}\n") open(out_full, 'w', encoding='utf-8').write('\n'.join(full + [f"==== {c}\n{t}\n" for c, t in texts])) open(out_compact, 'w', encoding='utf-8').write('\n'.join(compact) + '\n\n#### FULL TEXT OF EACH LICENSE USED ABOVE (each given once)\n\n' + '\n\n'.join(f"==== {c}\n{t}\n" for c, t in texts))