def _check_python_file(self, fname: str) -> None: from efrotools import get_public_license, PYVER with open(fname, encoding='utf-8') as infile: contents = infile.read() lines = contents.splitlines() # Make sure all standalone scripts are pointing to the right # version of python (with a few exceptions where it needs to # differ) if contents.startswith('#!/'): copyrightline = 1 if fname not in ['tools/vmshell']: if not contents.startswith(f'#!/usr/bin/env python{PYVER}'): raise CleanError(f'Incorrect shebang (first line) for ' f'{fname}.') else: copyrightline = 0 # Special case: it there's spinoff autogenerate notice there, # look below it. if (lines[copyrightline] == '' and 'THIS FILE IS AUTOGENERATED' in lines[copyrightline + 1]): copyrightline += 2 # In all cases, look for our one-line legal notice. # In the public case, look for the rest of our public license too. if self._license_line_checks: public_license = get_public_license('python') private_license = '# ' + get_legal_notice_private() lnum = copyrightline if len(lines) < lnum + 1: raise RuntimeError('Not enough lines in file:', fname) disable_note = ('NOTE: You can disable license line' ' checks by adding "license_line_checks": false\n' 'to the root dict in config/localconfig.json.\n' 'see https://ballistica.net/wiki' '/Knowledge-Nuggets#' 'hello-world-creating-a-new-game-type') if self._public: # Check for public license only. if lines[lnum] != public_license: raise CleanError(f'License text not found' f" at '{fname}' line {lnum+1};" f' please correct.\n' f'Expected text is: {public_license}\n' f'{disable_note}') else: # Check for public or private license. if (lines[lnum] != public_license and lines[lnum] != private_license): raise CleanError(f'License text not found' f" at '{fname}' line {lnum+1};" f' please correct.\n' f'Expected text (for public files):' f' {public_license}\n' f'Expected text (for private files):' f' {private_license}\n' f'{disable_note}')
def _check_makefiles(self) -> None: from efrotools import get_public_license # Run a few sanity checks on whatever makefiles we come across. fnames = subprocess.run('find . -maxdepth 3 -name Makefile', shell=True, capture_output=True, check=True).stdout.decode().split() fnames = [n for n in fnames if '/build/' not in n] for fname in fnames: with open(fname, encoding='utf-8') as infile: makefile = infile.read() if self._public: public_license = get_public_license('makefile') if public_license not in makefile: raise CleanError(f'Pub license not found in {fname}.') else: if (get_legal_notice_private() not in makefile and get_public_license('makefile') not in makefile): raise CleanError( f'Priv or pub legal not found in {fname}.')
def generate(projroot: str, infilename: str, outfilename: str) -> None: """Main script entry point.""" from batools.project import project_centric_path out = (get_public_license('python') + f'\n"""Enum vals generated by {__name__}; do not edit by hand."""' f'\n\nfrom enum import Enum\n') out += _gen_enums(infilename) path = project_centric_path(projroot=projroot, path=outfilename) print(f'Meta-building {Clr.BLD}{path}{Clr.RST}') os.makedirs(os.path.dirname(outfilename), exist_ok=True) with open(outfilename, 'w', encoding='utf-8') as outfile: outfile.write(out)
def _check_c_license(self, fname: str, lines: list[str]) -> None: from efrotools import get_public_license # Look for public license line (public or private repo) # or private license line (private repo only) line_private = '// ' + get_legal_notice_private() line_public = get_public_license('c++') lnum = 0 if self._public: if lines[lnum] != line_public: # Allow auto-correcting from private to public line allow_auto = lines[lnum] == line_private self._add_line_correction(fname, line_number=lnum, expected=line_public, can_auto_update=allow_auto) else: if lines[lnum] not in [line_public, line_private]: self._add_line_correction(fname, line_number=lnum, expected=line_private, can_auto_update=False)
def generate(sources_hash: str, outfilename: str) -> None: """Run the actual generation from within the game.""" import _ba as module from efrotools import get_public_license, PYVER import types funcnames = [] classnames = [] for entry in (e for e in dir(module) if not e.startswith('__')): if isinstance(getattr(module, entry), types.BuiltinFunctionType): funcnames.append(entry) elif isinstance(getattr(module, entry), type): classnames.append(entry) elif entry == 'app': # Ignore _ba.app. continue else: raise Exception( f'found unknown obj {entry}, {getattr(module, entry)}') funcnames.sort() classnames.sort() out = (get_public_license('python') + '\n' '#\n' '"""A dummy stub module for the real _ba.\n' '\n' 'The real _ba is a compiled extension module and only available\n' 'in the live game. This dummy module allows Pylint/Mypy/etc. to\n' 'function reasonably well outside of the game.\n' '\n' 'Make sure this file is never included in an actual game distro!\n' '\n' 'Ideally this should be a stub (.pyi) file, but we\'d need\n' 'to make sure that it still works with all our tools\n' '(mypy, pylint, pycharm).\n' '\n' 'NOTE: This file was autogenerated by ' + __name__ + '; ' 'do not edit by hand.\n' '"""\n' '\n' # '# (hash we can use to see if this file is out of date)\n' # '# SOURCES_HASH='+sources_hash+'\n' # '\n' '# I\'m sorry Pylint. I know this file saddens you. Be strong.\n' '# pylint: disable=useless-suppression\n' '# pylint: disable=unnecessary-pass\n' '# pylint: disable=use-dict-literal\n' '# pylint: disable=use-list-literal\n' '# pylint: disable=unused-argument\n' '# pylint: disable=missing-docstring\n' '# pylint: disable=too-many-locals\n' '# pylint: disable=redefined-builtin\n' '# pylint: disable=too-many-lines\n' '# pylint: disable=redefined-outer-name\n' '# pylint: disable=invalid-name\n' '# pylint: disable=no-value-for-parameter\n' '\n' 'from __future__ import annotations\n' '\n' 'from typing import TYPE_CHECKING, overload, Sequence, TypeVar\n' '\n' 'from ba._generated.enums import TimeFormat, TimeType\n' '\n' 'if TYPE_CHECKING:\n' ' from typing import Any, Callable, Optional, Union, Literal\n' ' from ba._app import App\n' ' import ba\n' '\n' '\n' "_T = TypeVar('_T')\n" '\n' 'app: App\n' '\n' 'def _uninferrable() -> Any:\n' ' """Get an "Any" in mypy and "uninferrable" in Pylint."""\n' ' # pylint: disable=undefined-variable\n' ' return _not_a_real_variable # type: ignore' '\n' '\n' ) # yapf: disable out += _writeclasses(module, classnames) out += _writefuncs(module, funcnames, indent=0, spacing=2, as_method=False) outhashpath = os.path.join(os.path.dirname(outfilename), '._ba_sources_hash') with open(outfilename, 'w', encoding='utf-8') as outfile: outfile.write(out) with open(outhashpath, 'w', encoding='utf-8') as outfile: outfile.write(sources_hash) # Lastly, format it. subprocess.run([f'python{PYVER}', '-m', 'yapf', '--in-place', outfilename], check=True)
def _check_python_file(self, fname: str) -> None: # pylint: disable=too-many-branches from efrotools import get_public_license with open(fname) as infile: contents = infile.read() lines = contents.splitlines() # Make sure all standalone scripts are pointing to the right # version of python (with a few exceptions where it needs to # differ) if contents.startswith('#!/'): copyrightline = 1 if fname not in [ 'tools/devtool', 'tools/version_utils', 'tools/vmshell' ]: if not contents.startswith('#!/usr/bin/env python3.7'): print(f'{Clr.RED}Incorrect shebang (first line) for ' f'{fname}.{Clr.RST}') sys.exit(255) else: copyrightline = 0 # Special case: it there's spinoff autogenerate notice there, # look below it. if (lines[copyrightline] == '' and 'THIS FILE IS AUTOGENERATED' in lines[copyrightline + 1]): copyrightline += 2 # In all cases, look for our one-line legal notice. # In the public case, look for the rest of our public license too. if self._copyright_checks: public_license = get_public_license('python') line = '# ' + get_legal_notice_private() # (Sanity check: public license's first line should be # same as priv) if line != public_license.splitlines()[0]: raise RuntimeError( 'Public license first line should match priv.') lnum = copyrightline if len(lines) < lnum + 1: raise RuntimeError('Not enough lines in file:', fname) if lines[lnum] != line: # Allow auto-correcting if it looks close already # (don't want to blow away an unrelated line) allow_auto = 'Copyright' in lines[ lnum] and 'Eric Froemling' in lines[lnum] self._add_line_correction(fname, line_number=lnum, expected=line, can_auto_update=allow_auto) found_intact_private = False else: found_intact_private = True if self._public: # Check for the full license. # If we can't find the full license but we found # a private-license line, offer to replace it with the # full one. Otherwise just complain and die. # Try to be reasonably certain it's not in here... definitely_have_full = public_license in contents might_have_full = ('Permission is hereby granted' in contents or 'THE SOFTWARE IS PROVIDED' in contents) # Only muck with it if we're not sure we've got it. if not definitely_have_full: if found_intact_private and not might_have_full: self._add_line_correction(fname, line_number=lnum, expected=public_license, can_auto_update=True) else: raise RuntimeError( f'Found incorrect license text in {fname};' f' please correct.')