diff --git a/.efrocachemap b/.efrocachemap index 52321f95..196bf33e 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4072,26 +4072,26 @@ "build/assets/workspace/ninjafightplug.py": "https://files.ballistica.net/cache/ba1/18/4b/787a9267e17be3c49966072581a5", "build/assets/workspace/onslaughtplug.py": "https://files.ballistica.net/cache/ba1/20/f6/4ce9bc3c1f3732f6adf8237fbe9b", "build/assets/workspace/runaroundplug.py": "https://files.ballistica.net/cache/ba1/a5/30/9058181df0b1255bf6950cbc7813", - "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/f2/dc/bf56d88353b11986373e899b5bf6", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/3c/43/731228e0f7c8e5396b06ca916ffd", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/71/24/b8bedec2fab3fd83381a23385a9a", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/5f/96/a43273ad50d90d9342f45c22c0e8", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/c9/75/393357c2a3f4d3eec2035bc3ecff", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/b0/85/d8778105cf5a536cb5e6e618c723", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/e8/41/5128ac78c21f238d0613ab8e2ece", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/7f/4d/96dadaf30683f4a69426518ca334", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/14/14/9f38fb471edd66d076b9d611ba55", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/12/37/d741089b132fbcb8b22d9795479a", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/b0/4f/e9ab4d8fc7405d9c8f667eaacb73", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/7e/2f/2e475906c60e960a63fdd3e5f24d", - "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/34/48/662a2168751cd25eaae50f0707df", - "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/1d/2f/ab1c77b292726178d0eb1f5699ad", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/44/b8/3c6e810fa14f014b9c91db7ab88a", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/14/59/2164e23d78a6b16a97b3bfe7bdb2", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/4f/91/83fa21e46183f74300820e98f4a1", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/61/f5/18b5f9055fb48a1c91ce25f45dee", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/87/53/556e49d3273d4be8bfeba546ecb8", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/98/9b/73c254c31fe68fc21cae40a1761e", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/dd/e6/324379d12d8773f739bbc1ee8742", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/78/24/27722a657784f579f5824b089691", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/83/df/eabeb7b26fb4b5bf8b899ebcd067", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/0a/99/6e19e6ad69a6f0fb4b73cacdd8e5", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/ad/bd/2f23197da76c148e41b359f0022a", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/29/29/2a87524a909d447f938762919de4", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/71/de/0b68a02b52ee2c5d356343dccd00", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/ea/22/0f260a3a44e4cfdf7706705c81a1", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/58/1e/023f58fe727fc70ade8ae6d5a880", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/1e/50/a607cd2582de36c989f0d470658e", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/81/e2/d816ac2f91de53683636bf3144bd", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/39/8e/756a7cc3ddcecd1146ea4589bf72", + "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/3c/ad/dcabf1359a1cae7c683036b23856", + "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/f9/06/3b9d1661d6e4cc21c42748db322b", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/cb/89/a4a0de5aaa1e1929871973587ddd", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/7a/3b/35ea440785a5ac39cb802b159c8a", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/53/9b/817e65aebfe3574d50385a08be52", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/84/b0/70de1c4c94a2c1c8d1fe54da695f", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/ba/ec/009c2ead7a78de11c0e55e447881", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/1f/8d/cdfe64de06a6861c27828b9120e8", "build/prefab/lib/linux_arm64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/29/dc/e5b08aae2dbe3222082aaa1e90e7", "build/prefab/lib/linux_arm64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/ce/bb/5796a83ce9d1c9cf58e08f3ff351", "build/prefab/lib/linux_arm64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/31/65/014221e46f7974f40aa84c8922dc", @@ -4108,14 +4108,14 @@ "build/prefab/lib/mac_x86_64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/14/4b/68a0ece3c1f191183b695cf45a4d", "build/prefab/lib/mac_x86_64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/1f/3f/d899a46cc0dc8bc4f1b38f9318a5", "build/prefab/lib/mac_x86_64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/de/99/95fdcb3f614a7b83ada148bca38d", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/74/cb/8be4f4dec7fd2bf11920a48c5446", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/ee/30/7d0a59834145150a5a64d29f2add", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/ad/53/a20f19509c6f90472c46004618e7", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/d7/20/8311a232ef822de08b7eea1185e5", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/f9/bb/cfb390d5f9d37997cacc804ee7ae", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/a6/fa/5651f4f3329109515ad15fbf7fbc", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/d8/49/3f000f69e2b50364b7d444f90b3f", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/7b/bd/aff34983fc5a00bfb59fd47d14cb", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/52/08/03398c2a3fcc29a99c687d5efbb4", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/e8/85/12943e9d34b55fd9a0d0ec0288ea", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/da/b1/a90ccef09b8305f32520688545bf", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/aa/a0/ce7ffae656e7877a72d35677114f", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/26/ef/dcfa52d8f4bb9c518c51687b2b3d", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/09/e9/31c76975c552041232b3ffd5fbf0", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/b0/35/a132ee60e1a20af514abe1276236", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/a4/94/64fc55a516281cc28fcfccebbd5b", "src/assets/ba_data/python/babase/_mgen/__init__.py": "https://files.ballistica.net/cache/ba1/52/c6/c11130af7b10d6c0321add5518fa", "src/assets/ba_data/python/babase/_mgen/enums.py": "https://files.ballistica.net/cache/ba1/38/c3/1dedd5e74f2508efc5974c8815a1", "src/ballistica/base/mgen/pyembed/binding_base.inc": "https://files.ballistica.net/cache/ba1/ea/6a/6a4721b144e5e297b542d2a0eea2", diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index e4100ccf..6ecadfcc 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1093,8 +1093,11 @@ fsets fsettings fsmetapackagename + fsmodulename + fsmodulepath fsname fspackagename + fspackagesroot fsplit fsrc fstab @@ -1359,6 +1362,7 @@ imghdr imgw importlines + importparts incentivized includelines includetest @@ -1574,8 +1578,10 @@ linenumber linenums linestart + linestripped linetype linetypes + linewords linflav linkstoryboards linkto @@ -1765,6 +1771,7 @@ moduledir modulefinder modulename + modulenames modulepath modutils moola diff --git a/CHANGELOG.md b/CHANGELOG.md index ee5eae32..2f0a8fc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.20 (build 21090, api 8, 2023-06-10) +### 1.7.20 (build 21091, api 8, 2023-06-12) - This seems like a good time for a `refactoring` release in anticipation of changes coming in 1.8. Basically this means that a lot of things will be diff --git a/ballisticakit-cmake/.idea/dictionaries/ericf.xml b/ballisticakit-cmake/.idea/dictionaries/ericf.xml index e1e330b6..bc7b5fd5 100644 --- a/ballisticakit-cmake/.idea/dictionaries/ericf.xml +++ b/ballisticakit-cmake/.idea/dictionaries/ericf.xml @@ -649,8 +649,11 @@ fsetname fsets fsmetapackagename + fsmodulename + fsmodulepath fsname fspackagename + fspackagesroot fstestspackagename fsum ftos @@ -799,6 +802,7 @@ imagewidget imayushsaini importlines + importparts incentivized includelines indata @@ -907,6 +911,8 @@ linebegin linemax linestart + linestripped + linewords linkstoryboards listobj llock @@ -1013,6 +1019,7 @@ modetype modstr modtime + modulenames moduletype momemtary morecnt diff --git a/src/assets/ba_data/python/baclassic/_tips.py b/src/assets/ba_data/python/baclassic/_tips.py index 9a63acb8..d356b664 100644 --- a/src/assets/ba_data/python/baclassic/_tips.py +++ b/src/assets/ba_data/python/baclassic/_tips.py @@ -7,7 +7,7 @@ from __future__ import annotations from typing import TYPE_CHECKING -import _babase +import babase if TYPE_CHECKING: pass @@ -105,7 +105,7 @@ def get_all_tips() -> list[str]: 'color of sparks from its fuse: yellow..orange..red..BOOM.' ), ] - app = _babase.app + app = babase.app if not app.iircade_mode: tips += [ 'If your framerate is choppy, try turning down resolution\nor ' diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index 0075dfca..0beaed6a 100644 --- a/src/assets/ba_data/python/baenv.py +++ b/src/assets/ba_data/python/baenv.py @@ -28,7 +28,7 @@ if TYPE_CHECKING: # Build number and version of the ballistica binary we expect to be # using. -TARGET_BALLISTICA_BUILD = 21090 +TARGET_BALLISTICA_BUILD = 21091 TARGET_BALLISTICA_VERSION = '1.7.20' _g_env_config: EnvConfig | None = None diff --git a/src/assets/ba_data/python/bascenev1/_dependency.py b/src/assets/ba_data/python/bascenev1/_dependency.py index ecbc1610..bbc956c0 100644 --- a/src/assets/ba_data/python/bascenev1/_dependency.py +++ b/src/assets/ba_data/python/bascenev1/_dependency.py @@ -7,7 +7,8 @@ from __future__ import annotations import weakref from typing import Generic, TypeVar, TYPE_CHECKING -import _babase +import babase + import _bascenev1 if TYPE_CHECKING: @@ -304,7 +305,7 @@ class AssetPackage(DependencyComponent): super().__init__() # This is used internally by the get_package_xxx calls. - self.context = _babase.ContextRef() + self.context = babase.ContextRef() entry = self._dep_entry() assert entry is not None @@ -424,7 +425,7 @@ def test_depset() -> None: # To test this, add prints on __del__ for stuff used above; # everything should be dead at this point if we have no cycles. print('everything should be cleaned up...') - _babase.quit() + babase.quit() class DependencyError(Exception): diff --git a/src/assets/ba_data/python/bascenev1/_hooks.py b/src/assets/ba_data/python/bascenev1/_hooks.py index 7ab12a7f..c531feb3 100644 --- a/src/assets/ba_data/python/bascenev1/_hooks.py +++ b/src/assets/ba_data/python/bascenev1/_hooks.py @@ -7,7 +7,8 @@ from __future__ import annotations from typing import TYPE_CHECKING -import _babase +import babase + import _bascenev1 if TYPE_CHECKING: @@ -17,9 +18,9 @@ if TYPE_CHECKING: def launch_main_menu_session() -> None: - assert _babase.app.classic is not None + assert babase.app.classic is not None - _bascenev1.new_host_session(_babase.app.classic.get_main_menu_session()) + _bascenev1.new_host_session(babase.app.classic.get_main_menu_session()) def get_player_icon(sessionplayer: bascenev1.SessionPlayer) -> dict[str, Any]: @@ -45,7 +46,7 @@ def filter_chat_message(msg: str, client_id: int) -> str | None: def local_chat_message(msg: str) -> None: - classic = _babase.app.classic + classic = babase.app.classic assert classic is not None party_window = ( None if classic.party_window is None else classic.party_window() diff --git a/src/assets/ba_data/python/bauiv1/_uitypes.py b/src/assets/ba_data/python/bauiv1/_uitypes.py index f8e5989a..b97ed2a3 100644 --- a/src/assets/ba_data/python/bauiv1/_uitypes.py +++ b/src/assets/ba_data/python/bauiv1/_uitypes.py @@ -9,7 +9,8 @@ import weakref from dataclasses import dataclass from typing import TYPE_CHECKING -import _babase +import babase + import _bauiv1 if TYPE_CHECKING: @@ -199,8 +200,8 @@ def uicleanupcheck(obj: Any, widget: bauiv1.Widget) -> None: widget.add_delete_callback(foobar) - assert _babase.app.classic is not None - _babase.app.ui_v1.cleanupchecks.append( + assert babase.app.classic is not None + babase.app.ui_v1.cleanupchecks.append( UICleanupCheck( obj=weakref.ref(obj), widget=widget, widget_death_time=None ) @@ -209,10 +210,10 @@ def uicleanupcheck(obj: Any, widget: bauiv1.Widget) -> None: def ui_upkeep() -> None: """Run UI cleanup checks, etc. should be called periodically.""" - assert _babase.app.classic is not None - ui = _babase.app.ui_v1 + assert babase.app.classic is not None + ui = babase.app.ui_v1 remainingchecks = [] - now = _babase.apptime() + now = babase.apptime() for check in ui.cleanupchecks: obj = check.obj() diff --git a/src/assets/ba_data/python/bauiv1/onscreenkeyboard.py b/src/assets/ba_data/python/bauiv1/onscreenkeyboard.py index 9c614c7a..a8e6098f 100644 --- a/src/assets/ba_data/python/bauiv1/onscreenkeyboard.py +++ b/src/assets/ba_data/python/bauiv1/onscreenkeyboard.py @@ -10,7 +10,7 @@ from typing import cast from typing import TYPE_CHECKING import babase -from _babase import screenmessage + import _bauiv1 from bauiv1._uitypes import Window @@ -379,12 +379,12 @@ class OnScreenKeyboardWindow(Window): self._load_keyboard() if len(kbexports) < 2: _bauiv1.getsound('error').play() - screenmessage( + babase.screenmessage( babase.Lstr(resource='keyboardNoOthersAvailableText'), color=(1, 0, 0), ) else: - screenmessage( + babase.screenmessage( babase.Lstr( resource='keyboardSwitchText', subs=[('${NAME}', self._keyboard.name)], diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index 077fad41..ac7ad7f4 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 = 21090; +const int kEngineBuildNumber = 21091; const char* kEngineVersion = "1.7.20"; auto MonolithicMain(const core::CoreConfig& core_config) -> int { diff --git a/tools/batools/build.py b/tools/batools/build.py index df5585ae..cd31fe69 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -35,11 +35,11 @@ class PyRequirement: # entries; this accounts for manual installations or other nonstandard # setups. -# Note 2: That is probably overkill. We can probably just replace -# this with a simple requirements.txt file, can't we? Feels like we're -# mostly reinventing the wheel here. We just need a clean way to -# check/list missing stuff without necessarily installing it. And as far -# as manually-installed bits, pip itself must have some way to allow for +# Note 2: That is probably overkill. We can probably just replace this +# with a simple requirements.txt file, can't we? Feels like we're mostly +# reinventing the wheel here. We just need a clean way to check/list +# missing stuff without necessarily installing it. And as far as +# manually-installed bits, pip itself must have some way to allow for # that, right?... PY_REQUIREMENTS = [ PyRequirement(modulename='pylint', minversion=[2, 17, 3]), @@ -63,9 +63,9 @@ PY_REQUIREMENTS = [ PyRequirement(pipname='filelock', minversion=[3, 12, 0]), ] -# Parts of full-tests suite we only run on particular days. -# (This runs in listed order so should be randomized by hand to avoid -# clustering similar tests too much) +# Parts of full-tests suite we only run on particular days. This runs in +# listed order so should be randomized by hand to avoid clustering +# similar tests too much. SPARSE_TEST_BUILDS: list[list[str]] = [ ['ios.pylibs.debug', 'android.pylibs.arm'], ['linux.package', 'android.pylibs.arm64'], @@ -82,8 +82,8 @@ SPARSE_TEST_BUILDS: list[list[str]] = [ ['mac.pylibs.debug', 'android.package'], ] -# Currently only doing sparse-tests in core; not spinoffs. -# (whole word will get subbed out in spinoffs so this will be false) +# Currently only doing sparse-tests in core; not spinoffs (whole word +# will get subbed out in spinoffs so this will evaluate to False). DO_SPARSE_TEST_BUILDS = 'ballistica' + 'kit' == 'ballisticakit' @@ -115,8 +115,9 @@ def lazybuild(target: str, category: LazyBuildCategory, command: str) -> None: LazyBuildContext( target=target, command=command, - # Since this category can kick off cleans and blow things away, - # its not safe to have multiple builds going with it at once. + # Since this category can kick off cleans and blow things + # away, its not safe to have multiple builds going with it + # at once. buildlockname=category.value, # Regular paths; changes to these will trigger meta build. srcpaths=[ @@ -124,12 +125,14 @@ def lazybuild(target: str, category: LazyBuildCategory, command: str) -> None: 'src/meta', 'src/ballistica/shared/foundation/types.h', ], - # Our meta Makefile targets generally don't list tools scripts - # that can affect their creation as sources, so let's set up - # a catch-all here: when any of our tools stuff changes we'll - # blow away all existing meta builds. - # Update: also including featureset-defs here; any time we're - # mucking with those it's good to start fresh to be sure. + # Our meta Makefile targets generally don't list tools + # scripts that can affect their creation as sources, so + # let's set up a catch-all here: when any of our tools stuff + # changes we'll blow away all existing meta builds. + # + # Update: also including featureset-defs here; any time + # we're mucking with those it's good to start fresh to be + # sure. srcpaths_fullclean=[ 'tools/efrotools', 'tools/efrotoolsinternal', @@ -198,9 +201,9 @@ def lazybuild(target: str, category: LazyBuildCategory, command: str) -> None: elif category is LazyBuildCategory.RESOURCES: LazyBuildContext( target=target, - # Even though this category currently doesn't run any - # clean commands, going to restrict to one use at a time for - # now in case we want to add that. + # Even though this category currently doesn't run any clean + # commands, going to restrict to one use at a time for now + # in case we want to add that. buildlockname=category.value, srcpaths=[ 'Makefile', @@ -214,18 +217,18 @@ def lazybuild(target: str, category: LazyBuildCategory, command: str) -> None: elif category is LazyBuildCategory.ASSETS: def _filefilter(root: str, filename: str) -> bool: - # Exclude tools/spinoff; it doesn't affect asset builds - # and we don't want to break if it is a symlink pointing - # to a not-present parent repo. + # Exclude tools/spinoff; it doesn't affect asset builds and + # we don't want to break if it is a symlink pointing to a + # not-present parent repo. if root == 'tools' and filename == 'spinoff': return False return True LazyBuildContext( target=target, - # Even though this category currently doesn't run any - # clean commands, going to restrict to one use at a time for - # now in case we want to add that. + # Even though this category currently doesn't run any clean + # commands, going to restrict to one use at a time for now + # in case we want to add that. buildlockname=category.value, srcpaths=[ 'Makefile', @@ -240,8 +243,8 @@ def lazybuild(target: str, category: LazyBuildCategory, command: str) -> None: elif category is LazyBuildCategory.DUMMYMODULES: def _filefilter(root: str, filename: str) -> bool: - # In our C++ sources, only look at stuff with 'python' in the - # name. + # In our C++ sources, only look at stuff with 'python' in + # the name. if root.startswith('ballistica'): return 'python' in filename @@ -250,8 +253,8 @@ def lazybuild(target: str, category: LazyBuildCategory, command: str) -> None: LazyBuildContext( target=target, - # This category builds binaries and other crazy stuff - # so we definitely want to restrict to one at a time. + # This category builds binaries and other crazy stuff so we + # definitely want to restrict to one at a time. buildlockname=category.value, srcpaths=[ 'config/featuresets', @@ -313,26 +316,28 @@ def gen_fulltest_buildfile_android() -> None: """ # pylint: disable=too-many-branches - # Its a pretty big time-suck building all architectures for - # all of our subplatforms, so lets usually just build a single one. - # We'll rotate it though and occasionally do all 4 at once just to - # be safe. + # Its a pretty big time-suck building all architectures for all of + # our subplatforms, so lets usually just build a single one. We'll + # rotate it though and occasionally do all 4 at once just to be + # safe. dayoffset = datetime.datetime.now().timetuple().tm_yday # Let's only do a full 'prod' once every two times through the loop. - # (it really should never catch anything that individual platforms don't) + # (it really should never catch anything that individual platforms + # don't) modes = ['arm', 'arm64', 'x86', 'x86_64'] modes += modes modes.append('prod') # By default we cycle through build architectures for each flavor. - # However, for minor flavor with low risk of platform-dependent breakage - # we stick to a single one to keep disk space costs lower. (build files - # amount to several gigs per mode per flavor) - # UPDATE: Now that we have CPU time to spare, we simply always do 'arm64' - # or 'prod' depending on build type; this results in 1 or 4 architectures - # worth of build files per flavor instead of 8 (prod + 4 singles) and - # keeps our daily runs identical. + # However, for minor flavor with low risk of platform-dependent + # breakage we stick to a single one to keep disk space costs lower. + # (build files amount to several gigs per mode per flavor) + # + # UPDATE: Now that we have CPU time to spare, we simply always do + # 'arm64' or 'prod' depending on build type; this results in 1 or 4 + # architectures worth of build files per flavor instead of 8 (prod + + # 4 singles) and keeps our daily runs identical. lightweight_flavors = {'template', 'arcade', 'demo', 'iircade'} lines = [] @@ -433,10 +438,10 @@ def gen_fulltest_buildfile_windows() -> None: lines: list[str] = [] - # We want to do one regular, one headless, and one oculus build, - # but let's switch up 32 or 64 bit based on the day. - # Also occasionally throw a release build in but stick to - # mostly debug builds to keep build times speedier. + # We want to do one regular, one headless, and one oculus build, but + # let's switch up 32 or 64 bit based on the day. Also occasionally + # throw a release build in but stick to mostly debug builds to keep + # build times speedier. pval1 = 'Win32' if dayoffset % 2 == 0 else 'x64' pval2 = 'Win32' if (dayoffset + 1) % 2 == 0 else 'x64' pval3 = 'Win32' if (dayoffset + 2) % 2 == 0 else 'x64' @@ -692,10 +697,11 @@ def checkenv() -> None: ) # Make sure rsync is version 3.1.0 or newer. - # Macs come with ancient rsync versions with significant downsides such - # as single second file mod time resolution which has started to cause - # problems with build setups. So now am trying to make sure my Macs - # have an up-to-date one installed (via homebrew). + # + # Macs come with ancient rsync versions with significant downsides + # such as single second file mod time resolution which has started + # to cause problems with build setups. So now am trying to make sure + # my Macs have an up-to-date one installed (via homebrew). rsyncver = tuple( int(s) for s in subprocess.run( @@ -772,8 +778,10 @@ def checkenv() -> None: ) from exc # Check for some required python modules. + # # FIXME: since all of these come from pip now, we should just use - # pip --list to check versions on everything instead of doing it ad-hoc. + # pip --list to check versions on everything instead of doing it + # ad-hoc. for req in PY_REQUIREMENTS: try: modname = req.modulename diff --git a/tools/batools/project/_checks.py b/tools/batools/project/_checks.py index df396736..6de16e06 100755 --- a/tools/batools/project/_checks.py +++ b/tools/batools/project/_checks.py @@ -277,6 +277,7 @@ def check_python_files(self: ProjectUpdater) -> None: from efrotools.code import get_script_filenames scriptfiles = get_script_filenames(Path(self.projroot)) + for fname in scriptfiles: _check_python_file(self, fname) @@ -289,6 +290,7 @@ def check_python_files(self: ProjectUpdater) -> None: 'src/assets/ba_data/python', 'src/meta', ] + # EXCEPT for the following specifics. ignores: dict[str, set[str]] = { 'tools': { @@ -337,58 +339,125 @@ def check_python_files(self: ProjectUpdater) -> None: def _check_python_file(self: ProjectUpdater, fname: str) -> None: - # pylint: disable=too-many-branches - - with open(fname, encoding='utf-8') as infile: + with open(os.path.join(self.projroot, 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 + _check_python_file_shebang(self, fname, contents) + _check_python_file_license(self, fname, lines) + _check_python_file_imports(self, fname, lines) - # 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 - if lines[copyrightline].startswith('# Synced from '): - copyrightline += 3 +def _check_python_file_imports( + self: ProjectUpdater, fname: str, lines: list[str] +) -> None: + # pylint: disable=too-many-locals + # pylint: disable=too-many-branches + fspackagesroot = 'src/assets/ba_data/python/' + + # Only checking modules that are part of a featureset. + if not fname.startswith(fspackagesroot): + return + parts = fname.split('/') + if parts[4].endswith('.py'): + return + fsmodulename = parts[4] for i, line in enumerate(lines): - # FIXME: update this for the new feature-set world. Perhaps we - # can screen for imports based on feature-set dependencies or - # perhaps we should not even try and just let feature-set test - # builds catch problems like that. - if bool(False): - # Stuff under the babase module. - if '/babase/' in fname: - # Don't allow importing ba at the top level from within babase. - if line == 'import babase': - raise CleanError( - f'{fname}:{i+1}: no top level babase imports allowed' - f' under babase module.' - ) - if '/bascenev1lib/' in fname: - # Don't allow importing _babase or _baplus anywhere here. - # (any internal needs should be in babase.internal) - if 'import _babase' in line: - raise CleanError( - f'{fname}:{i+1}: _babase or _baplus imports not' - f' allowed under bascenev1lib.' - ) + linestripped = line.strip() + top_level = not line.startswith(' ') + linewords = linestripped.split(' ') + if len(linewords) < 2: + continue + + if linewords[0] == 'import': + assert len(linewords) > 1 + modulepath = linewords[1] + importparts = None + elif ( + linewords[0] == 'from' + and len(linewords) > 2 + and linewords[2] == 'import' + ): + modulepath = linewords[1] + importparts = linewords[3:] + else: + continue + + # Look for simple cases of 'from foo import bar'. + if ( + importparts + and '(' not in importparts[0] + and ',' not in importparts[0] + ): + single_import = importparts[0] + else: + single_import = None + + modulenames = modulepath.split('.') + + # These are fine. + if modulenames[0] in {'__future__', '__main__'}: + continue + + # If they're importing a _foo module, make sure they are part of + # featureset foo. + if ( + modulenames[0].startswith('_') + and modulenames[0] != f'_{fsmodulename}' + ): + raise CleanError( + f'{fname}:{i+1}: Import of private module {modulenames[0]}' + f' not allowed from this featureset package ({fsmodulename}).' + ) + + # If they're importing foo._bar, make sure they are part of + # featureset foo. + for modulename in modulenames[1:]: + if modulename.startswith('_') and modulenames[0] != fsmodulename: + raise CleanError( + f'{fname}:{i+1}: import of private module {modulepath}' + f' not allowed from this featureset package' + f' ({fsmodulename}).' + ) + + # Modules under feature-set package foo should never be using + # the top level feature-set package foo directly; only + # individual modules under it. (foo._bar, etc). Doing this can + # lead to lots of import order problems. We currently make an + # exception for anything *not* top-level which covers + # TYPE_CHECKING blocks and functions, both of which should be + # generally ok. + if top_level and modulepath == fsmodulename: + # Also we want to allow 'from foo import bar' *IF* bar is a + # submodule. Note: currently only looking for single + # submodule imports but I don't think we ever import + # multiple. + if importparts is not None and single_import is not None: + fsmodulepath = os.path.join( + self.projroot, fspackagesroot, fsmodulename + ) + assert os.path.exists(fsmodulepath) + is_submodule_import = os.path.isdir( + f'{fsmodulepath}/{single_import}' + ) or os.path.isfile(f'{fsmodulepath}/{single_import}.py') + else: + is_submodule_import = False + + if not is_submodule_import: + raise CleanError( + f'{fname}:{i+1}: Top level package module {modulepath}' + f' should not be imported by its own code' + ' (except for within TYPE_CHECKING blocks or functions).' + ' Import stuff from submodules directly.' + ) + + +def _check_python_file_license( + self: ProjectUpdater, fname: str, lines: list[str] +) -> None: + copyrightline = _calc_python_file_copyright_line(self, lines) # 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: @@ -430,6 +499,43 @@ def _check_python_file(self: ProjectUpdater, fname: str) -> None: ) +def _calc_python_file_copyright_line( + self: ProjectUpdater, lines: list[str] +) -> int: + del self # Unused. + copyrightline = 1 if lines[0].startswith('#!/') else 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 + + if lines[copyrightline].startswith('# Synced from '): + copyrightline += 3 + + return copyrightline + + +def _check_python_file_shebang( + self: ProjectUpdater, fname: str, contents: str +) -> None: + del self # Unused. + if contents.startswith('#!'): + # Make sure all standalone scripts are pointing to the right version + # of Python (with a few exceptions where it needs to differ) + if fname not in ['tools/vmshell']: + expected = f'#!/usr/bin/env python{PYVER}' + if not contents.startswith(expected): + raise CleanError( + f'Incorrect shebang (first line) for {fname}.\n' + f'Expected:\n{expected}\n\n' + f'Found:\n{contents.splitlines()[0]}' + ) + + def _contains_only_pycache_and_cruft(path: str) -> bool: for _root, dirs, files in os.walk(path, topdown=True): # Skip over hidden and pycache dirs. diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py index c848a9bf..4b6cada4 100644 --- a/tools/efrotools/code.py +++ b/tools/efrotools/code.py @@ -6,8 +6,8 @@ from __future__ import annotations import os -import subprocess import sys +import subprocess from pathlib import Path from typing import TYPE_CHECKING @@ -196,8 +196,17 @@ def get_code_filenames(projroot: Path, include_generated: bool) -> list[str]: pass else: codefilenames.append(path) - codefilenames.sort() - return codefilenames + out = sorted(codefilenames) + + # Watch for breakage. + if not out: + print( + 'WARNING: get_code_filename returning no results;' + ' is something broken?', + file=sys.stderr, + ) + + return out def black_base_args() -> list[str]: @@ -291,20 +300,33 @@ def get_script_filenames(projroot: Path) -> list[str]: """Return the Python filenames to lint-check or auto-format.""" from efrotools import getconfig + proot = f'{projroot}/' + filenames = set() places = getconfig(projroot).get('python_source_dirs', None) if places is None: raise RuntimeError('python_source_dirs not declared in config') for place in places: - for root, _dirs, files in os.walk(place): + for root, _dirs, files in os.walk(os.path.join(projroot, place)): for fname in files: fnamefull = os.path.join(root, fname) # Skip symlinks (we conceivably operate on the original too) if os.path.islink(fnamefull): continue if _should_include_script(fnamefull): - filenames.add(fnamefull) - return sorted(list(f for f in filenames if 'flycheck_' not in f)) + assert fnamefull.startswith(proot) + filenames.add(fnamefull.removeprefix(proot)) + out = sorted(list(f for f in filenames if 'flycheck_' not in f)) + + # Watch for breakage. + if not out: + print( + 'WARNING: get_script_filename returning no results;' + ' is something broken?', + file=sys.stderr, + ) + + return out def runpylint(projroot: Path, filenames: list[str]) -> None: