diff --git a/.efrocachemap b/.efrocachemap index 6cf03f6d..d2b823d3 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4068,26 +4068,26 @@ "build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1", "build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae", "build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599", - "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "2668b413da2d1dd597a6a6b8c6ae9ee8", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "5d38798c383cae78c227c427ae967281", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "0df69387ebe2fb149694a267a1df4c24", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "153abebe70483d17d933127e894908c4", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "fd6768fe1167b8e24db5eb9e33360456", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "8377309f0d570de541e9210752463bab", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "b4b774fef02d72f58f8083430cbc8334", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "9b100c7bf923a8f01de1b5984f62e7e5", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "ac5ecfa5b0e10bcc0d333875bfff9d29", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "241d315d379eb10ec7c2c7ccc8efa99e", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "9d57aaf4d56398e67695659eedce569c", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "d22fdee9f1355dd8965f56a97518ad85", - "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "b85955e00c3a076af273849fd436b18c", - "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "a044700e51b426cd333ab32308bfc033", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "e4bcb7821639ffb7e5b0616d509d3c3d", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "91a3fcefaf965260efb388f4477c8ce3", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "4a54dbbe24033a862a2dac3eb76f98b3", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "c82081e53a00d198137c934efae1ed72", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "d8ee381eafbca03eee21e1218935f499", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "f6e6fc30a1d2a3ccb2d5f43bf91c4402", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "884277e559d840df55f7e0dd1c186949", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "38240f93c1ae9065cf671be2e7620684", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "0480c97db92676754cf9552ee462dccb", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "052b4f4804e30da165744893e84d4a64", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "32d4c7a4bdac7a8cb12d4b42868a5979", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "42649b501212bea15f4b2f2741583339", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "03cbedec6c8f294d7fe57a6dc64803e8", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "37b2c536cd841b40319b0efae40471ce", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "85a86ab24f3a35bff85a9954d7be135a", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "5399d3f4924909ca1c0878f347e20a10", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "70784b57105accc067608e1ea50c2fbc", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "58559f7512a300586b8141591a21564e", + "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "851e1bcd5f12bcee1a2bb9d503ab90a3", + "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "8e98e2bb1d7d9fa34f873fd2b7d82138", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "9df874848d2f0cedc815f216f9ab2958", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "49107effdf5c1ee5a0533251a99f9f6a", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "dd131f742bc7780f30fe9bbcd547a662", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "b59086a58f9fd2148c186a4974ef59dd", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "03e1623b3a2826161a8a13b09d8ee9b6", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "56b977883c7374d3feb006a9d40c3e18", "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "85ba4e81a1f7ae2cff4b1355eb49904f", "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "498921f7eb2afd327d4b900cb70e31f9", "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "85ba4e81a1f7ae2cff4b1355eb49904f", @@ -4104,14 +4104,14 @@ "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "0ab638b6602610bdaf432e3cc2464080", "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "92394eb19387c363471ce134ac9e6a1b", "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "0ab638b6602610bdaf432e3cc2464080", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "0016db9bd4fbf158d19f5a6e84aa2f74", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "40c9f4c7076ef9013dde9afd05d89b95", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "4e74f1959b833486aa1cee0affa1aaef", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "4e39a9a8222a683aa074a0698c26c498", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "9509a8782beb8fd0fc477d0afe3cc6c0", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "091fd49e9c75b202b4f481b65f91a100", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "87567923e411e713f82429f56abd9d84", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "5e6707e7b299474ae4a43a1df2919a55", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "d5b059c1be49152dcc400302e27406a7", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "606d781277bc8f8cd51b7fff37b405eb", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "0204082e71fe83d5e7e9688120a5c47d", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "453de7f93862b35f208993f32a681fa1", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "e7f61245af268edad9ad09250e934a71", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "e35706c767bba1f98c568ca1f1c54361", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "71de54551134cfb4e993d8897ba91dd3", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "88053eee3b28eb71e65eef0910d02a2d", "src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c", "src/assets/ba_data/python/babase/_mgen/enums.py": "f8cd3af311ac63147882590123b78318", "src/ballistica/base/mgen/pyembed/binding_base.inc": "eeddad968b176000e31c65be6206a2bc", diff --git a/CHANGELOG.md b/CHANGELOG.md index 69f2c519..335b2ef7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.25 (build 21206, api 8, 2023-07-29) +### 1.7.25 (build 21208, api 8, 2023-07-31) - `getconfig` and `setconfig` in `efrotools` are now `getprojectconfig` and `setprojectconfig` (to reflect the file name changes that happened in 1.7.20). @@ -31,6 +31,12 @@ dirs and only moved into their final locations once that completes successfully. Its extra important to be safe now that its possible to share local efrocache dirs between projects or otherwise keep them around longer. +- Experimenting a bit with adding support for + [Pyright](https://github.com/microsoft/pyright) type-checking. This could + theoretically allow for a really great interactive Python environment in + Visual Studio Code (and potentially other editors), so am seeing if it is + worth officially supporting in addition to or as a replacement for Mypy. See + `tools/pcommand pyright` ### 1.7.24 (build 21199, api 8, 2023-07-27) diff --git a/config/toolconfigsrc/dir-locals.el b/config/toolconfigsrc/dir-locals.el index a1859328..082be0f4 100644 --- a/config/toolconfigsrc/dir-locals.el +++ b/config/toolconfigsrc/dir-locals.el @@ -1,34 +1,9 @@ -;;; Directory Local Variables for emacs clang flycheck -;;; For more information see (info "(emacs) Directory Variables") +;; -*- lexical-binding: t; -*- -;;; Turn flycheck mode on for our c++ stuff and tell jedi where to look for our python stuff. ( - ;; (c++-mode (eval . (flycheck-mode))) - - (python-ts-mode (jedi:server-args . ("--sys-path" "__EFRO_PROJECT_ROOT__/tools" - "--sys-path" "__EFRO_PROJECT_ROOT__/src/assets/ba_data/python" - "--sys-path" "__EFRO_PROJECT_ROOT__/build/dummymodules" - ;; "--log-level" "DEBUG" "--log" "/Users/ericf/Desktop/jedilog" - )) - (python-black-extra-args . __PYTHON_BLACK_EXTRA_ARGS__)) - - ;; Shorter name in projectile status bar to save valuable space. - (nil . ((projectile-project-name . "__EFRO_PROJECT_SHORTNAME__"))) - - ;; Projectile indexing and search will ignore the following - ;; (in addition to git-ignored stuff which it ignores by default) - ;; NOTE TO SELF: this means searches in spinoff projects will mostly fail - ;; because everything is gitignored; should search in parent repo instead. - (nil . ((projectile-globally-ignored-directories . ("docs" - "submodules" - "src/external" - "src/assets/ba_data/python-site-packages" - "src/assets/pylib-android" - "src/assets/pylib-apple" - "src/assets/windows")))) - - ;; Trying to get project.el to work the same as projectile since its built in. + ;; Specify some extra paths that project.el searches and whatnot should ignore. + ;; Note that gitignored stuff is ignored implicitly. (nil . ((project-vc-ignores . ("docs" "submodules" "src/external" @@ -37,4 +12,32 @@ "src/assets/pylib-apple" "src/assets/windows")))) + ;; Set up clangd as our C++ language server. + (c++-ts-mode . ((eglot-server-programs . ((c++-ts-mode . ("clangd" "--compile-commands-dir=.cache/compile_commands_db")))))) + + ;; Set up python-lsp-server as our Python language server. + (python-ts-mode . ( + (eglot-server-programs . ( + (python-ts-mode . ("__EFRO_PY_BIN__" "-m" "pylsp")))) + (python-shell-interpreter . "__EFRO_PY_BIN__") + (eglot-workspace-configuration . ( + (:pylsp . (:plugins ( + :pylint (:enabled t) + :flake8 (:enabled :json-false) + :pycodestyle (:enabled :json-false) + :mccabe (:enabled :json-false) + :autopep8 (:enabled :json-false) + :pyflakes (:enabled :json-false) + :rope_autoimport (:enabled :json-false) + :rope_completion (:enabled :json-false) + :rope_rename (:enabled :json-false) + :yapf (:enabled :json-false) + :black (:enabled t + :skip_string_normalization t + :line_length 80 + :cache_config t) + :jedi (:extra_paths [__EFRO_PYTHON_PATHS_Q_REL_STR__]) + :pylsp_mypy (:enabled t + :live_mode nil + :dmypy t)))))))) ) diff --git a/src/assets/ba_data/python/babase/__init__.py b/src/assets/ba_data/python/babase/__init__.py index 7388a683..ea5343bc 100644 --- a/src/assets/ba_data/python/babase/__init__.py +++ b/src/assets/ba_data/python/babase/__init__.py @@ -17,6 +17,7 @@ a more focused way. from efro.util import set_canonical_module_names + import _babase from _babase import ( add_clean_frame_callback, diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index 95e1b4b7..037a7dfd 100644 --- a/src/assets/ba_data/python/baenv.py +++ b/src/assets/ba_data/python/baenv.py @@ -24,6 +24,7 @@ from dataclasses import dataclass from typing import TYPE_CHECKING import __main__ + if TYPE_CHECKING: from efro.log import LogHandler @@ -50,7 +51,7 @@ if TYPE_CHECKING: # Build number and version of the ballistica binary we expect to be # using. -TARGET_BALLISTICA_BUILD = 21206 +TARGET_BALLISTICA_BUILD = 21208 TARGET_BALLISTICA_VERSION = '1.7.25' diff --git a/src/assets/ba_data/python/bascenev1/_activity.py b/src/assets/ba_data/python/bascenev1/_activity.py index 77be627e..9a7863ec 100644 --- a/src/assets/ba_data/python/bascenev1/_activity.py +++ b/src/assets/ba_data/python/bascenev1/_activity.py @@ -18,8 +18,8 @@ if TYPE_CHECKING: from typing import Any import bascenev1 -PlayerT = TypeVar('PlayerT', bound=Player) -TeamT = TypeVar('TeamT', bound=Team) +PlayerT = TypeVar("PlayerT", bound=Player) +TeamT = TypeVar("TeamT", bound=Team) class Activity(DependencyComponent, Generic[PlayerT, TeamT]): @@ -300,7 +300,7 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): self._expire() else: raise RuntimeError( - f'destroy() called when' f' already expired for {self}' + f"destroy() called when" f" already expired for {self}" ) def retain_actor(self, actor: bascenev1.Actor) -> None: @@ -410,7 +410,7 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): # Set up the globals node based on our settings. with self.context: - glb = self._globalsnode = _bascenev1.newnode('globals') + glb = self._globalsnode = _bascenev1.newnode("globals") # Now that it's going to be front and center, # set some global values based on what the activity wants. @@ -452,7 +452,7 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): try: self.on_transition_in() except Exception: - logging.exception('Error in on_transition_in for %s.', self) + logging.exception("Error in on_transition_in for %s.", self) # Tell the C++ layer that this activity is the main one, so it uses # settings from our globals, directs various events to us, etc. @@ -466,7 +466,7 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): try: self.on_transition_out() except Exception: - logging.exception('Error in on_transition_out for %s.', self) + logging.exception("Error in on_transition_out for %s.", self) def begin(self, session: bascenev1.Session) -> None: """Begin the activity. @@ -562,7 +562,7 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): try: self.on_player_join(player) except Exception: - logging.exception('Error in on_player_join for %s.', self) + logging.exception("Error in on_player_join for %s.", self) def remove_player(self, sessionplayer: bascenev1.SessionPlayer) -> None: """Remove a player from the Activity while it is running. @@ -592,11 +592,11 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): try: self.on_player_leave(player) except Exception: - logging.exception('Error in on_player_leave for %s.', self) + logging.exception("Error in on_player_leave for %s.", self) try: player.leave() except Exception: - logging.exception('Error on leave for %s in %s.', player, self) + logging.exception("Error on leave for %s in %s.", player, self) self._reset_session_player_for_no_activity(sessionplayer) @@ -621,7 +621,7 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): try: self.on_team_join(team) except Exception: - logging.exception('Error in on_team_join for %s.', self) + logging.exception("Error in on_team_join for %s.", self) def remove_team(self, sessionteam: bascenev1.SessionTeam) -> None: """Remove a team from a Running Activity @@ -643,11 +643,11 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): try: self.on_team_leave(team) except Exception: - logging.exception('Error in on_team_leave for %s.', self) + logging.exception("Error in on_team_leave for %s.", self) try: team.leave() except Exception: - logging.exception('Error on leave for %s in %s.', team, self) + logging.exception("Error on leave for %s in %s.", team, self) sessionteam.activityteam = None @@ -668,7 +668,7 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): sessionplayer.setnode(None) except Exception: logging.exception( - 'Error resetting SessionPlayer node on %s for %s.', + "Error resetting SessionPlayer node on %s for %s.", sessionplayer, self, ) @@ -676,7 +676,7 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): sessionplayer.resetinput() except Exception: logging.exception( - 'Error resetting SessionPlayer input on %s for %s.', + "Error resetting SessionPlayer input on %s for %s.", sessionplayer, self, ) @@ -701,17 +701,17 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): if not isinstance(self._playertype, type): self._playertype = Player print( - f'ERROR: {type(self)} was not passed a Player' - f' type argument; please explicitly pass bascenev1.Player' - f' if you do not want to override it.' + f"ERROR: {type(self)} was not passed a Player" + f" type argument; please explicitly pass bascenev1.Player" + f" if you do not want to override it." ) self._teamtype = type(self).__orig_bases__[-1].__args__[1] if not isinstance(self._teamtype, type): self._teamtype = Team print( - f'ERROR: {type(self)} was not passed a Team' - f' type argument; please explicitly pass bascenev1.Team' - f' if you do not want to override it.' + f"ERROR: {type(self)} was not passed a Team" + f" type argument; please explicitly pass bascenev1.Team" + f" if you do not want to override it." ) assert issubclass(self._playertype, Player) assert issubclass(self._teamtype, Team) @@ -729,24 +729,24 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): try: activity = activity_ref() print( - 'ERROR: Activity is not dying when expected:', + "ERROR: Activity is not dying when expected:", activity, - '(warning ' + str(counter[0] + 1) + ')', + "(warning " + str(counter[0] + 1) + ")", ) print( - 'This means something is still strong-referencing it.\n' - 'Check out methods such as efro.debug.printrefs() to' - ' help debug this sort of thing.' + "This means something is still strong-referencing it.\n" + "Check out methods such as efro.debug.printrefs() to" + " help debug this sort of thing." ) # Note: no longer calling gc.get_referrers() here because it's # usage can bork stuff. (see notes at top of efro.debug) counter[0] += 1 if counter[0] == 4: - print('Killing app due to stuck activity... :-(') + print("Killing app due to stuck activity... :-(") babase.quit() except Exception: - logging.exception('Error on _check_activity_death.') + logging.exception("Error on _check_activity_death.") def _expire(self) -> None: """Put the activity in a state where it can be garbage-collected. @@ -760,12 +760,12 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): try: self.on_expire() except Exception: - logging.exception('Error in Activity on_expire() for %s.', self) + logging.exception("Error in Activity on_expire() for %s.", self) try: self._customdata = None except Exception: - logging.exception('Error clearing customdata for %s.', self) + logging.exception("Error clearing customdata for %s.", self) # Don't want to be holding any delay-delete refs at this point. self._prune_delay_deletes() @@ -780,7 +780,7 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): try: self._activity_data.expire() except Exception: - logging.exception('Error expiring _activity_data for %s.', self) + logging.exception("Error expiring _activity_data for %s.", self) def _expire_actors(self) -> None: # Expire all Actors. @@ -792,7 +792,7 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): actor.on_expire() except Exception: logging.exception( - 'Error in Actor.on_expire() for %s.', actor_ref() + "Error in Actor.on_expire() for %s.", actor_ref() ) def _expire_players(self) -> None: @@ -810,7 +810,7 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): try: player.expire() except Exception: - logging.exception('Error expiring %s.', player) + logging.exception("Error expiring %s.", player) # Reset the SessionPlayer to a not-in-an-activity state. try: @@ -821,7 +821,7 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): # until now whos underlying SessionPlayer left long ago... pass except Exception: - logging.exception('Error expiring %s.', player) + logging.exception("Error expiring %s.", player) def _expire_teams(self) -> None: # Issue warnings for any teams that left the game but don't @@ -838,7 +838,7 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): try: team.expire() except Exception: - logging.exception('Error expiring %s.', team) + logging.exception("Error expiring %s.", team) try: sessionteam = team.sessionteam @@ -850,7 +850,7 @@ class Activity(DependencyComponent, Generic[PlayerT, TeamT]): # player/team has left the game) pass except Exception: - logging.exception('Error expiring Team %s.', team) + logging.exception("Error expiring Team %s.", team) def _prune_delay_deletes(self) -> None: self._delay_delete_players.clear() diff --git a/src/assets/ba_data/python/bascenev1/_activitytypes.py b/src/assets/ba_data/python/bascenev1/_activitytypes.py index c4facbc0..c0e410e1 100644 --- a/src/assets/ba_data/python/bascenev1/_activitytypes.py +++ b/src/assets/ba_data/python/bascenev1/_activitytypes.py @@ -15,6 +15,7 @@ from bascenev1._player import EmptyPlayer # pylint: disable=W0611 from bascenev1._team import EmptyTeam # pylint: disable=W0611 from bascenev1._music import MusicType, setmusic + if TYPE_CHECKING: import bascenev1 from bascenev1._lobby import JoinInfo diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index 5de4aa6e..013cc28c 100644 --- a/src/ballistica/shared/ballistica.cc +++ b/src/ballistica/shared/ballistica.cc @@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int { namespace ballistica { // These are set automatically via script; don't modify them here. -const int kEngineBuildNumber = 21206; +const int kEngineBuildNumber = 21208; const char* kEngineVersion = "1.7.25"; #if BA_MONOLITHIC_BUILD diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py index f1cd9393..2abf998d 100644 --- a/tools/efrotools/code.py +++ b/tools/efrotools/code.py @@ -22,7 +22,6 @@ from efrotools.filecache import FileCache # pylint: enable=useless-suppression, wrong-import-order - if TYPE_CHECKING: from typing import Any diff --git a/tools/efrotools/efrocache.py b/tools/efrotools/efrocache.py index 3555fb11..86e4d6ce 100644 --- a/tools/efrotools/efrocache.py +++ b/tools/efrotools/efrocache.py @@ -566,7 +566,11 @@ def _check_warm_start_entries(entries: list[tuple[str, str]]) -> None: def warm_start_cache() -> None: - """Run a pre-pass on the efrocache to improve efficiency.""" + """Run a pre-pass on the efrocache to improve efficiency. + + This may fetch an initial cache archive, batch update mod times + to reflect new cache maps, etc. + """ import tempfile base_url = get_repository_base_url() diff --git a/tools/efrotools/pcommand.py b/tools/efrotools/pcommand.py index 59cd2d8d..5b04a0de 100644 --- a/tools/efrotools/pcommand.py +++ b/tools/efrotools/pcommand.py @@ -449,125 +449,16 @@ def androidstudiocode() -> None: def tool_config_install() -> None: """Install a tool config file (with some filtering).""" - from efro.terminal import Clr from efro.error import CleanError + import efrotools.toolconfig + if len(sys.argv) != 4: raise CleanError('expected 2 args') src = Path(sys.argv[2]) dst = Path(sys.argv[3]) - print(f'Creating tool config: {Clr.BLD}{dst}{Clr.RST}') - - with src.open(encoding='utf-8') as infile: - cfg = infile.read() - - # Some substitutions, etc. - cfg = _filter_tool_config(cfg) - - # Add an auto-generated notice. - comment = None - if dst.name in ['.dir-locals.el']: - comment = ';;' - elif dst.name in [ - '.mypy.ini', - '.pycheckers', - '.pylintrc', - '.style.yapf', - '.clang-format', - '.editorconfig', - ]: - comment = '#' - if comment is not None: - cfg = ( - f'{comment} THIS FILE WAS AUTOGENERATED; DO NOT EDIT.\n' - f'{comment} Source: {src}.\n\n' + cfg - ) - - with dst.open('w', encoding='utf-8') as outfile: - outfile.write(cfg) - - -def _filter_tool_config(cfg: str) -> str: - import textwrap - - from efrotools import getprojectconfig - - # Stick project-root wherever they want. - cfg = cfg.replace('__EFRO_PROJECT_ROOT__', str(PROJROOT)) - - # Stick a colon-separated list of project Python paths wherever they want. - name = '__EFRO_PYTHON_PATHS__' - if name in cfg: - pypaths = getprojectconfig(PROJROOT).get('python_paths') - if pypaths is None: - raise RuntimeError('python_paths not set in project config') - assert not any(' ' in p for p in pypaths) - cfg = cfg.replace(name, ':'.join(f'{PROJROOT}/{p}' for p in pypaths)) - - # Short project name. - short_names = { - 'ballistica-internal': 'ba-i', - 'ballistica': 'ba', - 'ballistica-master-server': 'bmas', - 'ballistica-master-server-legacy': 'bmasl', - 'ballistica-server-node': 'basn', - } - shortname = short_names.get(PROJROOT.name, PROJROOT.name) - cfg = cfg.replace('__EFRO_PROJECT_SHORTNAME__', shortname) - - mypy_standard_settings = textwrap.dedent( - """ - # We don't want all of our plain scripts complaining - # about __main__ being redefined. - scripts_are_modules = True - - # Try to be as strict as we can about using types everywhere. - no_implicit_optional = True - warn_unused_ignores = True - warn_no_return = True - warn_return_any = True - warn_redundant_casts = True - warn_unreachable = True - warn_unused_configs = True - disallow_incomplete_defs = True - disallow_untyped_defs = True - disallow_untyped_decorators = True - disallow_untyped_calls = True - disallow_any_unimported = True - disallow_subclassing_any = True - strict_equality = True - local_partial_types = True - no_implicit_reexport = True - - enable_error_code = redundant-expr, truthy-bool, \ -truthy-function, unused-awaitable - """ - ).strip() - - cfg = cfg.replace('__EFRO_MYPY_STANDARD_SETTINGS__', mypy_standard_settings) - - name = '__PYTHON_BLACK_EXTRA_ARGS__' - if name in cfg: - from efrotools.code import black_base_args - - bargs = black_base_args() - assert bargs[2] == 'black' - cfg = cfg.replace( - name, '(' + ' '.join(f'"{b}"' for b in bargs[3:]) + ')' - ) - - # Gen a pylint init hook which sets up our python paths. - pylint_init_tag = '__EFRO_PYLINT_INIT__' - if pylint_init_tag in cfg: - pypaths = getprojectconfig(PROJROOT).get('python_paths') - if pypaths is None: - raise RuntimeError('python_paths not set in project config') - cstr = 'init-hook=import sys;' - for path in pypaths: - cstr += f" sys.path.append('{PROJROOT}/{path}');" - cfg = cfg.replace(pylint_init_tag, cstr) - return cfg + efrotools.toolconfig.install_tool_config(PROJROOT, src, dst) def sync_all() -> None: diff --git a/tools/efrotools/toolconfig.py b/tools/efrotools/toolconfig.py new file mode 100644 index 00000000..08a64e7f --- /dev/null +++ b/tools/efrotools/toolconfig.py @@ -0,0 +1,155 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Functionality for wrangling tool config files. + +This lets us auto-populate values such as python-paths or versions +into tool config files automatically instead of having to update +everything everywhere manually. It also provides a centralized location +for some tool defaults across all my projects. +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +from efro.terminal import Clr + +if TYPE_CHECKING: + from pathlib import Path + + +def install_tool_config(projroot: Path, src: Path, dst: Path) -> None: + """Install a config.""" + print(f'Creating tool config: {Clr.BLD}{dst}{Clr.RST}') + + with src.open(encoding='utf-8') as infile: + cfg = infile.read() + + # Some substitutions, etc. + cfg = _filter_tool_config(projroot, cfg) + + # Add an auto-generated notice. + comment = None + if dst.name in ['.dir-locals.el']: + comment = ';;' + elif dst.name in [ + '.mypy.ini', + '.pycheckers', + '.pylintrc', + '.style.yapf', + '.clang-format', + '.editorconfig', + ]: + comment = '#' + if comment is not None: + cfg = ( + f'{comment} THIS FILE WAS AUTOGENERATED; DO NOT EDIT.\n' + f'{comment} Source: {src}.\n\n' + cfg + ) + + with dst.open('w', encoding='utf-8') as outfile: + outfile.write(cfg) + + +def _filter_tool_config(projroot: Path, cfg: str) -> str: + # pylint: disable=too-many-locals + import textwrap + + from efrotools import getprojectconfig, PYVER + + # Stick project-root wherever they want. + cfg = cfg.replace('__EFRO_PROJECT_ROOT__', str(projroot)) + + # Project Python version; '3.11', etc. + name = '__EFRO_PY_VER__' + if name in cfg: + cfg = cfg.replace(name, PYVER) + + # Project Python version as a binary name; 'python3.11', etc. + name = '__EFRO_PY_BIN__' + if name in cfg: + cfg = cfg.replace(name, f'python{PYVER}') + + # Colon-separated list of project Python paths. + name = '__EFRO_PYTHON_PATHS__' + if name in cfg: + pypaths = getprojectconfig(projroot).get('python_paths') + if pypaths is None: + raise RuntimeError('python_paths not set in project config') + assert not any(' ' in p for p in pypaths) + cfg = cfg.replace(name, ':'.join(f'{projroot}/{p}' for p in pypaths)) + + # Quoted relative space-separated list of project Python paths. + name = '__EFRO_PYTHON_PATHS_Q_REL_STR__' + if name in cfg: + pypaths = getprojectconfig(projroot).get('python_paths') + if pypaths is None: + raise RuntimeError('python_paths not set in project config') + assert not any(' ' in p for p in pypaths) + cfg = cfg.replace(name, ' '.join(f'"{p}"' for p in pypaths)) + + # Short project name. + short_names = { + 'ballistica-internal': 'ba-i', + 'ballistica': 'ba', + 'ballistica-master-server': 'bmas', + 'ballistica-master-server-legacy': 'bmasl', + 'ballistica-server-node': 'basn', + } + shortname = short_names.get(projroot.name, projroot.name) + cfg = cfg.replace('__EFRO_PROJECT_SHORTNAME__', shortname) + + mypy_standard_settings = textwrap.dedent( + """ + # We don't want all of our plain scripts complaining + # about __main__ being redefined. + scripts_are_modules = True + + # Try to be as strict as we can about using types everywhere. + no_implicit_optional = True + warn_unused_ignores = True + warn_no_return = True + warn_return_any = True + warn_redundant_casts = True + warn_unreachable = True + warn_unused_configs = True + disallow_incomplete_defs = True + disallow_untyped_defs = True + disallow_untyped_decorators = True + disallow_untyped_calls = True + disallow_any_unimported = True + disallow_subclassing_any = True + strict_equality = True + local_partial_types = True + no_implicit_reexport = True + + enable_error_code = redundant-expr, truthy-bool, \ +truthy-function, unused-awaitable + """ + ).strip() + + cfg = cfg.replace('__EFRO_MYPY_STANDARD_SETTINGS__', mypy_standard_settings) + + name = '__PYTHON_BLACK_EXTRA_ARGS__' + if name in cfg: + from efrotools.code import black_base_args + + bargs = black_base_args() + assert bargs[2] == 'black' + cfg = cfg.replace( + name, '(' + ' '.join(f'"{b}"' for b in bargs[3:]) + ')' + ) + + # Gen a pylint init hook that sets up our Python paths. + pylint_init_tag = '__EFRO_PYLINT_INIT__' + if pylint_init_tag in cfg: + pypaths = getprojectconfig(projroot).get('python_paths') + if pypaths is None: + raise RuntimeError('python_paths not set in project config') + cstr = 'init-hook=import sys;' + # Stuff our paths in at the beginning in the order they appear + # in our projectconfig. + for i, path in enumerate(pypaths): + cstr += f" sys.path.insert({i}, '{projroot}/{path}');" + cfg = cfg.replace(pylint_init_tag, cstr) + return cfg diff --git a/tools/pcommand b/tools/pcommand index afc42b70..ca90021e 100755 --- a/tools/pcommand +++ b/tools/pcommand @@ -15,6 +15,7 @@ from __future__ import annotations from typing import TYPE_CHECKING + # Pull in commands we want to expose. Its more efficient to define them in # modules rather than inline here because we'll be able to load them via pyc. # pylint: disable=unused-import