diff --git a/.bazelrc b/.bazelrc index c6b70f1631..8d5c99fb4e 100644 --- a/.bazelrc +++ b/.bazelrc @@ -20,4 +20,5 @@ build --spawn_strategy=standalone build --strategy=SwiftCompile=worker -common --registry=https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/ +#common --registry=https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/ + diff --git a/.sourcekit-lsp/config.json b/.sourcekit-lsp/config.json deleted file mode 100644 index 8837d09328..0000000000 --- a/.sourcekit-lsp/config.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "backgroundIndexing": true, - "backgroundPreparationMode": "build", - "buildServerWorkspaceRequestsTimeout": 999, - "buildSettingsTimeout": 999, - "defaultWorkspaceType": "buildServer", - "logging": { - "level": "error", - "privacyLevel": "sensitive" - } -} diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 8ca4257fe3..0000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "configurations": [ - { - "name": "Debug Telegram", - "type": "lldb-dap", - "request": "attach", - "preLaunchTask": "_launch_telegram", - "debuggerRoot": "${workspaceFolder}", - "attachCommands": [ - "process connect connect://localhost:6667" - ], - "internalConsoleOptions": "openOnSessionStart", - "timeout": 1000 - }, - { - "name": "Restart Debug Telegram", - "type": "lldb-dap", - "request": "attach", - "preLaunchTask": "Restart Telegram Debug", - "debuggerRoot": "${workspaceFolder}", - "attachCommands": [ - "process connect connect://localhost:6667" - ], - "internalConsoleOptions": "openOnSessionStart", - "timeout": 1000 - }, - ], - "options": { - "console": "integratedTerminal", - } -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index a949672dbf..12db7dafb0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,7 @@ { + "swift.disableSwiftPackageManagerIntegration": true, + "swift.autoGenerateLaunchConfigurations": false, + "swift.disableAutoResolve": true, "search.followSymlinks": false, "files.exclude": { ".git/**": true @@ -22,5 +25,5 @@ ] } }, - "swift.sourcekit-lsp.serverPath": "${workspaceFolder}/build-input/sourcekit-lsp", + "swift.sourcekit-lsp.serverPath": "${workspace}/build-input/sourcekit-lsp" } diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index efabdea411..0000000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "Build Telegram", - "type": "shell", - "command": "${workspaceFolder}/build-input/bazel-8.4.2-darwin-arm64", - "args": [ - "build", - "Telegram/Telegram", - "--features=swift.use_global_module_cache", - "--verbose_failures", - "--remote_cache_async", - "--features=swift.skip_function_bodies_for_derived_files", - "--jobs=16", - "--define=buildNumber=10000", - "--define=telegramVersion=12.2.2", - "--disk_cache=${HOME}/telegram-bazel-cache", - "-c", - "dbg", - "--ios_multi_cpus=sim_arm64", - "--watchos_cpus=arm64_32", - "--features=swift.enable_batch_mode" - ], - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [], - "runOptions": { - "instanceLimit": 1 - } - }, - // Hidden never-ending task that handles the launch / debugging bits for Cmd+Shift+D. - // The problemMatcher field defines when the task is effectively ready to be debugged - // by the attach task in launch.json. - { - "label": "_launch_telegram", - "type": "shell", - "command": "./scripts/launch_and_debug.sh", - "presentation": { - "reveal": "always" - }, - "hide": true, - "isBackground": true, - "problemMatcher": [ - { - "pattern": [ - { - "regexp": "\\b\\B", - "file": 1, - "location": 2, - "message": 3 - } - ], - "background": { - "activeOnStart": true, - "beginsPattern": "^.*Building....*", - "endsPattern": "^.*Listening to port 6667 for a connection from .*" - } - } - ], - "runOptions": { - "instanceLimit": 1 - } - }, - { - "label": "Stream SourceKitBazelBSP Logs", - "type": "shell", - "command": "log stream --process sourcekit-bazel-bsp --debug", - "problemMatcher": [], - "isBackground": false, - "presentation": { - "reveal": "always", - "panel": "dedicated" - } - }, - { - "label": "Stop Telegram Debug Session", - "type": "shell", - "command": "pkill -f 'launch_and_debug.sh' || true; lsof -ti:6667 | xargs kill -9 2>/dev/null || true", - "problemMatcher": [], - "presentation": { - "reveal": "silent", - "close": true - } - }, - { - "label": "Restart Telegram Debug", - "dependsOrder": "sequence", - "dependsOn": [ - "Stop Telegram Debug Session", - "_launch_telegram" - ], - "problemMatcher": [], - "presentation": { - "reveal": "always" - } - } - ] -} \ No newline at end of file diff --git a/BUILD.bazel b/BUILD.bazel index 37688a7cca..198f54a501 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -5,6 +5,13 @@ setup_sourcekit_bsp( bazel_wrapper = "./build-input/bazel-8.4.2-darwin-arm64", files_to_watch = [ "**/*.swift", + "**/*.h", + "**/*.m", + "**/*.mm", + "**/*.c", + "**/*.cc", + "**/*.cpp", + "**/*.hpp", ], index_flags = [ "config=index_build", diff --git a/MODULE.bazel b/MODULE.bazel index d8d3618a90..99b68b09ef 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -63,8 +63,8 @@ local_path_override( path = "./build-input/configuration-repository", ) -bazel_dep(name = "sourcekit_bazel_bsp", version = "0.3.0") +bazel_dep(name = "sourcekit_bazel_bsp", version = "0.7.1") local_path_override( module_name = "sourcekit_bazel_bsp", path = "build-system/bazel-rules/sourcekit-bazel-bsp", -) \ No newline at end of file +) diff --git a/scripts/Telegram b/scripts/Telegram deleted file mode 100755 index efd83a0c5d..0000000000 --- a/scripts/Telegram +++ /dev/null @@ -1,755 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2020 The Bazel Authors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Invoked by `bazel run` to launch *_application targets in the simulator.""" - -# This script works in one of two modes. -# -# If either --ios_simulator_version or --ios_simulator_device were not -# passed to bazel: -# -# 1. Discovers a simulator compatible with the minimum_os of the -# *_application target, preferring already-booted simulators -# if possible -# 2. Boots the simulator if needed -# 3. Installs and launches the application -# 4. Displays the application's output on the console -# -# This mode does not kill running simulators or shutdown or delete the simulator -# after it completes. -# -# If --ios_simulator_version and --ios_simulator_device were both passed -# to bazel: -# -# 1. Creates a new temporary simulator by running "simctl create ..." -# 2. Boots the new temporary simulator -# 3. Installs and launches the application -# 4. Displays the application's output on the console -# 5. When done, shuts down and deletes the newly-created simulator -# -# All environment variables with names starting with "IOS_" are passed to the -# application, after stripping the prefix "IOS_". - -import collections.abc -import contextlib -import json -import logging -import os -import os.path -import pathlib -import platform -import plistlib -import shutil -import subprocess -import sys -import tempfile -import time -from typing import Dict, Optional -import zipfile - - -# Custom type for methods yielding an Apple simulator UDID. -AppleSimulatorUDID = collections.abc.Generator[str, None, None] - - -logging.basicConfig( - format="%(asctime)s.%(msecs)03d %(levelname)s %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", - level=logging.INFO, -) -logger = logging.getLogger(__name__) - -if platform.system() != "Darwin": - raise Exception( - "Cannot run Apple platform application targets on a non-mac machine." - ) - - -class DeviceType(collections.abc.Mapping): - """Wraps the `devicetype` dictionary from `simctl list -j`. - - Provides an ordering so iPhones > iPads. In addition, maintains the - original order from `simctl list` as `simctl_list_index` to ensure - newer device types are sorted after older device types. - """ - - def __init__(self, device_type, simctl_list_index): - self.device_type = device_type - self.simctl_list_index = simctl_list_index - - def __getitem__(self, name): - return self.device_type[name] - - def __iter__(self): - return iter(self.device_type) - - def __len__(self): - return len(self.device_type) - - def __repr__(self): - return self["name"] + " (" + self["identifier"] + ")" - - def __lt__(self, other): - # Order iPhones ahead of (later in the list than) iPads. - if self.is_ipad() and other.is_iphone(): - return True - elif self.is_iphone() and other.is_ipad(): - return False - # Order device types from the same product family in the same order - # as `simctl list`. - return self.simctl_list_index < other.simctl_list_index - - def supports_platform_type(self, platform_type: str) -> bool: - """Returns boolean to indicate if device supports given Apple platform type.""" - if platform_type == "ios": - return self.is_iphone() or self.is_ipad() - elif platform_type == "tvos": - return self.is_apple_tv() - elif platform_type == "watchos": - return self.is_apple_watch() - elif platform_type == "visionos": - return self.is_apple_vision() - else: - raise ValueError( - f"Apple platform type not supported for simulator: {platform_type}." - ) - - def is_apple_tv(self) -> bool: - return self.has_product_family_or_identifier("Apple TV") - - def is_apple_watch(self) -> bool: - return self.has_product_family_or_identifier("Apple Watch") - - def is_apple_vision(self) -> bool: - return self.has_product_family_or_identifier("Apple Vision") - - def is_iphone(self) -> bool: - return self.has_product_family_or_identifier("iPhone") - - def is_ipad(self) -> bool: - return self.has_product_family_or_identifier("iPad") - - def has_product_family_or_identifier(self, device_type: str) -> bool: - product_family = self.get("productFamily") - if product_family: - return product_family == device_type - # Some older simulators are missing `productFamily`. Try to guess from the - # identifier. - return device_type in self["identifier"] - - -class Device(collections.abc.Mapping): - """Wraps the `device` dictionary from `simctl list -j`. - - Provides an ordering so booted devices > shutdown devices, delegating - to `DeviceType` order when both devices have the same state. - """ - - def __init__(self, device, device_type): - self.device = device - self.device_type = device_type - - def is_shutdown(self): - return self["state"] == "Shutdown" - - def is_booted(self): - return self["state"] == "Booted" - - def __getitem__(self, name): - return self.device[name] - - def __iter__(self): - return iter(self.device) - - def __len__(self): - return len(self.device) - - def __repr__(self): - return self["name"] + "(" + self["udid"] + ")" - - def __lt__(self, other): - if self.is_shutdown() and other.is_booted(): - return True - elif self.is_booted() and other.is_shutdown(): - return False - else: - return self.device_type < other.device_type - - -def minimum_os_to_simctl_runtime_version(minimum_os: str) -> int: - """Converts a minimum OS string to a simctl RuntimeVersion integer. - - Args: - minimum_os: A string in the form '12.2' or '13.2.3'. - - Returns: - An integer in the form 0xAABBCC, where AA is the major version, BB is - the minor version, and CC is the micro version. - """ - # Pad the minimum OS version to major.minor.micro. - minimum_os_components = (minimum_os.split(".") + ["0"] * 3)[:3] - result = 0 - for component in minimum_os_components: - result = (result << 8) | int(component) - return result - - -def discover_best_compatible_simulator( - *, - platform_type: str, - simctl_path: str, - minimum_os: str, - sim_device: str, - sim_os_version: str, -) -> (Optional[DeviceType], Optional[Device]): - """Discovers the best compatible simulator device type and device. - - Args: - platform_type: The Apple platform type for the given *_application() target. - simctl_path: The path to the `simctl` binary. - minimum_os: The minimum OS version required by the *_application() target. - sim_device: Optional name of the device (e.g. "iPhone 8 Plus"). - sim_os_version: Optional version of the Apple platform runtime (e.g. - "13.2"). - - Returns: - A tuple (device_type, device) containing the DeviceType and Device - of the best compatible simulator (might be None if no match was found). - - Raises: - subprocess.SubprocessError: if `simctl list` fails or times out. - """ - # The `simctl list` CLI provides only very basic case-insensitive description - # matching search term functionality. - # - # This code needs to enforce a numeric floor on `minimum_os`, so it directly - # parses the JSON output by `simctl list` instead of repeatedly invoking - # `simctl list` with search terms. - cmd = [simctl_path, "list", "-j"] - with subprocess.Popen(cmd, stdout=subprocess.PIPE) as process: - simctl_data = json.load(process.stdout) - if process.wait() != os.EX_OK: - raise subprocess.CalledProcessError(process.returncode, cmd) - compatible_device_types = [] - minimum_runtime_version = minimum_os_to_simctl_runtime_version(minimum_os) - # Prepare the device name for case-insensitive matching. - sim_device = sim_device and sim_device.casefold() - # `simctl list` orders device types from oldest to newest. Remember - # the index of each device type to preserve that ordering when - # sorting device types. - for simctl_list_index, device_type in enumerate(simctl_data["devicetypes"]): - device_type = DeviceType(device_type, simctl_list_index) - if not device_type.supports_platform_type(platform_type): - continue - # Some older simulators are missing `maxRuntimeVersion`. Assume those - # simulators support all OSes (even though it's not true). - max_runtime_version = device_type.get("maxRuntimeVersion") - if max_runtime_version and max_runtime_version < minimum_runtime_version: - continue - if sim_device and device_type["name"].casefold() != sim_device: - continue - compatible_device_types.append(device_type) - compatible_device_types.sort() - # logger.info( - # "Found %d potentialcompatible device types.", len(compatible_device_types) - # ) - compatible_runtime_identifiers = set() - for runtime in simctl_data["runtimes"]: - if not runtime["isAvailable"]: - continue - if sim_os_version and runtime["version"] != sim_os_version: - continue - compatible_runtime_identifiers.add(runtime["identifier"]) - compatible_devices = [] - for runtime_identifier, devices in simctl_data["devices"].items(): - if runtime_identifier not in compatible_runtime_identifiers: - continue - for device in devices: - if not device["isAvailable"]: - continue - compatible_device = None - for device_type in compatible_device_types: - if device["deviceTypeIdentifier"] == device_type["identifier"]: - compatible_device = Device(device, device_type) - break - if not compatible_device: - continue - compatible_devices.append(compatible_device) - compatible_devices.sort() - logger.debug("Found %d compatible devices.", len(compatible_devices)) - if compatible_device_types: - best_compatible_device_type = compatible_device_types[-1] - else: - best_compatible_device_type = None - if compatible_devices: - best_compatible_device = compatible_devices[-1] - else: - best_compatible_device = None - return (best_compatible_device_type, best_compatible_device) - - -def persistent_simulator( - *, - platform_type: str, - simctl_path: str, - minimum_os: str, - sim_device: str, - sim_os_version: str, -) -> str: - """Finds or creates a persistent compatible Apple simulator. - - Boots the simulator if needed. Does not shut down or delete the simulator when - done. - - Args: - platform_type: The Apple platform type for the given *_application() target. - simctl_path: The path to the `simctl` binary. - minimum_os: The minimum OS version required by the *_application() target. - sim_device: Optional name of the device (e.g. "iPhone 8 Plus"). - sim_os_version: Optional version of the Apple platform runtime (e.g. - "13.2"). - - Returns: - The UDID of the compatible Apple simulator. - - Raises: - Exception: if a compatible simulator was not found. - """ - (best_compatible_device_type, best_compatible_device) = ( - discover_best_compatible_simulator( - platform_type=platform_type, - simctl_path=simctl_path, - minimum_os=minimum_os, - sim_device=sim_device, - sim_os_version=sim_os_version, - ) - ) - if best_compatible_device: - udid = best_compatible_device["udid"] - if best_compatible_device.is_shutdown(): - logger.debug("Booting compatible device: %s", best_compatible_device) - subprocess.run([simctl_path, "boot", udid], check=True) - else: - logger.debug("Using compatible device: %s", best_compatible_device) - return udid - if best_compatible_device_type: - device_name = best_compatible_device_type["name"] - device_id = best_compatible_device_type["identifier"] - # logger.info("Creating new %s simulator", device_name) - create_result = subprocess.run( - [simctl_path, "create", device_name, device_id], - encoding="utf-8", - stdout=subprocess.PIPE, - check=True, - ) - udid = create_result.stdout.rstrip() - logger.debug("Created new simulator: %s", udid) - return udid - raise Exception( - f"Could not find or create a simulator for the {platform_type} platform" - f"compatible with minimum OS version {minimum_os} (device name " - f"{sim_device}, OS version {sim_os_version})" - ) - - -def wait_for_sim_to_boot(simctl_path: str, udid: str) -> bool: - """Blocks until the given simulator is booted. - - Args: - simctl_path: The path to the `simctl` binary. - udid: The identifier of the simulator to wait for. - - Returns: - True if the simulator boots within 60 seconds, False otherwise. - """ - logger.info("Waiting for simulator to boot...") - for _ in range(0, 60): - # The expected output of "simctl list" is like: - # -- iOS 8.4 -- - # iPhone 5s (E946FA1C-26AB-465C-A7AC-24750D520BEA) (Shutdown) - # TestDevice (8491C4BC-B18E-4E2D-934A-54FA76365E48) (Booted) - # So if there's any booted simulator, $booted_device will not be empty. - #logger.info("will list devices with udid: %s", udid) - simctl_list_result = subprocess.run( - [simctl_path, "list", "devices"], - encoding="utf-8", - check=True, - stdout=subprocess.PIPE, - ) - #logger.info(simctl_list_result.stdout) - for line in simctl_list_result.stdout.split("\n"): - if line.find(udid) != -1 and line.find("Booted") != -1: - logger.debug("Simulator is booted.") - # Simulator is booted. - return True - logger.debug("Simulator not booted, still waiting...") - time.sleep(1) - return False - - -def boot_simulator(*, developer_path: str, simctl_path: str, udid: str) -> None: - """Launches the Apple simulator for the given identifier. - - Ensures the Simulator process is in the foreground. - - Args: - developer_path: The path to /Applications/Xcode.app/Contents/Developer. - simctl_path: The path to the `simctl` binary. - udid: The identifier of the simulator to wait for. - - Raises: - Exception: if the simulator did not launch within 60 seconds. - """ - logger.info("Launching simulator with udid: %s", udid) - # Using subprocess.Popen() to launch Simulator.app and then - # `osascript -e "tell application \"Simulator\" to activate" is racy - # and can fail with: - # - # Simulator got an error: Connection is invalid. (-609) - # - # This is likely because the newly-spawned Simulator.app process - # hasn't had time to connect to the Apple Events system which - # `osascript` relies on. - simulator_path = os.path.join(developer_path, "Applications/Simulator.app") - subprocess.run( - ["open", "-a", simulator_path, "--args", "-CurrentDeviceUDID", udid], - check=True, - ) - logger.debug("Simulator launched.") - if not wait_for_sim_to_boot(simctl_path, udid): - raise Exception("Failed to launch simulator with UDID: " + udid) - - -@contextlib.contextmanager -def temporary_simulator( - *, platform_type: str, simctl_path: str, device: str, version: str -) -> AppleSimulatorUDID: - """Creates a temporary Apple simulator, cleaned up automatically upon close. - - Args: - platform_type: The Apple platform type for the given *_application() target. - simctl_path: The path to the `simctl` binary. - device: The name of the device (e.g. "iPhone 8 Plus"). - version: The version of the Apple platform runtime (e.g. "13.2"). - - Yields: - The UDID of the newly-created Apple simulator. - """ - runtime_version_name = version.replace(".", "-") - # capitalizes 'os' from Apple platform type string (e.g. watchos -> watchOS) - runtime_platform = platform_type[0:-2].lower() + platform_type[-2:].upper() - # logger.info("Creating simulator, device=%s, version=%s", device, version) - simctl_create_result = subprocess.run( - [ - simctl_path, - "create", - "TestDevice", - device, - "{prefix}.{runtime_platform}-{runtime_version_name}".format( - prefix="com.apple.CoreSimulator.SimRuntime", - runtime_platform=runtime_platform, - runtime_version_name=runtime_version_name, - ), - ], - encoding="utf-8", - check=True, - stdout=subprocess.PIPE, - ) - udid = simctl_create_result.stdout.rstrip() - try: - logger.info("Killing all running simulators...") - subprocess.run( - ["pkill", "Simulator"], stderr=subprocess.DEVNULL, check=False - ) - yield udid - finally: - logger.info("Shutting down simulator with udid: %s", udid) - subprocess.run( - [simctl_path, "shutdown", udid], stderr=subprocess.DEVNULL, check=False - ) - logger.info("Deleting simulator with udid: %s", udid) - subprocess.run([simctl_path, "delete", udid], check=True) - - -def register_dsyms(dsyms_dir: str): - """Adds all dSYMs in `dsyms_dir` to the symbolscache. - - Args: - dsyms_dir: Path to directory potentially containing dSYMs - """ - symbolscache_command = [ - "/usr/bin/symbolscache", - "delete", - "--tag", - "Bazel", - "compact", - "add", - "--tag", - "Bazel", - ] + [ - a - for a in pathlib.Path(dsyms_dir).glob( - "**/*.dSYM/Contents/Resources/DWARF/*" - ) - ] - logger.debug("Running command: %s", symbolscache_command) - result = subprocess.run( - symbolscache_command, - capture_output=True, - check=True, - encoding="utf-8", - text=True, - ) - logger.debug("symbolscache output: %s", result.stdout) - - -@contextlib.contextmanager -def extracted_app( - application_output_path: str, app_name: str -) -> AppleSimulatorUDID: - """Extracts Foo.app from *_application() output and makes it writable. - - Args: - application_output_path: Path to the output of an `*_application()`. If the - path is a directory, copies it to a temporary directory and makes the - contents writable, as `simctl install` fails to install an `.app` that is - read-only. If the path is an .ipa archive, unzips it to a temporary - directory. - app_name: The name of the application (e.g. "Foo" for "Foo.app"). - - Yields: - Path to Foo.app in temporary directory (re-used if already present). - """ - if os.path.isdir(application_output_path): - # Re-use the same path for each run and rsync to it (reducing - # copies). Ensure the result is writable, or `simctl install` will - # fail with `Unhandled error domain NSPOSIXErrorDomain, code 13`. - dst_dir = os.path.join(tempfile.gettempdir(), "bazel_temp_" + app_name) - os.makedirs(dst_dir, exist_ok=True) - - # NOTE: use `which` to find the path to `rsync`. - # In macOS 15.4, the system `rsync` is using `openrsync` which contains some permission issues. - # This allows users to workaround the issue by overriding the system `rsync` with a working version. - # Remove this once we no longer support macOS versions with broken `rsync`. - rsync_path = shutil.which("rsync") - - rsync_command = [ - rsync_path, - "--archive", - "--delete", - "--checksum", - "--chmod=u+w", - "--verbose", - # The output path might itself be a symlink; resolve to the - # real path so rsync doesn't just copy the symlink. - os.path.realpath(application_output_path), - dst_dir, - ] - logger.debug( - "Found app directory: %s, running command: %s", - application_output_path, - rsync_command, - ) - result = subprocess.run( - rsync_command, - capture_output=True, - check=True, - encoding="utf-8", - text=True, - ) - logger.debug("rsync output: %s", result.stdout) - yield os.path.join(dst_dir, app_name + ".app") - else: - # Create a new temporary directory for each run, deleting it - # afterwards (there's no efficient way to "sync" an unzip, so this - # can't re-use the output directory). - with tempfile.TemporaryDirectory(prefix="bazel_temp") as temp_dir: - logger.debug( - "Unzipping IPA from %s to %s", application_output_path, temp_dir - ) - with zipfile.ZipFile(application_output_path) as ipa_zipfile: - ipa_zipfile.extractall(temp_dir) - yield os.path.join(temp_dir, "Payload", app_name + ".app") - - -def bundle_id(bundle_path: str) -> str: - """Returns the bundle ID given a bundle directory path.""" - info_plist_path = os.path.join(bundle_path, "Info.plist") - with open(info_plist_path, mode="rb") as plist_file: - plist = plistlib.load(plist_file) - return plist["CFBundleIdentifier"] - - -def simctl_launch_environ() -> Dict[str, str]: - """Calculates an environment dictionary for running `simctl launch`.""" - # Pass environment variables prefixed with "IOS_" to the simulator, replace - # the prefix with "SIMCTL_CHILD_". bazel adds "IOS_" to the env vars which - # will be passed to the app as prefix to differentiate from other env vars. We - # replace the prefix "IOS_" with "SIMCTL_CHILD_" here, because "simctl" only - # pass the env vars prefixed with "SIMCTL_CHILD_" to the app. - result = {} - for k, v in os.environ.items(): - if not k.startswith("IOS_"): - continue - new_key = k.replace("IOS_", "SIMCTL_CHILD_", 1) - result[new_key] = v - if "IDE_DISABLED_OS_ACTIVITY_DT_MODE" not in os.environ: - # Ensure os_log() mirrors writes to stderr. (lldb and Xcode set this - # environment variable as well.) - result["SIMCTL_CHILD_OS_ACTIVITY_DT_MODE"] = "enable" - return result - - -@contextlib.contextmanager -def apple_simulator( - *, - platform_type: str, - simctl_path: str, - minimum_os: str, - sim_device: str, - sim_os_version: str, -) -> AppleSimulatorUDID: - """Finds either a temporary or persistent Apple simulator based on args. - - Args: - platform_type: The Apple platform type for the given *_application() target. - simctl_path: The path to the `simctl` binary. - minimum_os: The minimum OS version required by the *_application() target. - sim_device: Optional name of the device (e.g. "iPhone 8 Plus"). - sim_os_version: Optional version of the Apple platform runtime (e.g. - "13.2"). - - Yields: - The UDID of the simulator. - """ - yield persistent_simulator( - platform_type=platform_type, - simctl_path=simctl_path, - minimum_os=minimum_os, - sim_device=sim_device, - sim_os_version=sim_os_version, - ) - - -def run_app_in_simulator( - *, - simulator_udid: str, - developer_path: str, - simctl_path: str, - application_output_path: str, - app_name: str, -) -> None: - """Installs and runs an app in the specified simulator. - - Args: - simulator_udid: The UDID of the simulator in which to run the app. - developer_path: The path to /Applications/Xcode.app/Contents/Developer. - simctl_path: The path to the `simctl` binary. - application_output_path: Path to the output of an `*_application()`. - app_name: The name of the application (e.g. "Foo" for "Foo.app"). - """ - boot_simulator( - developer_path=developer_path, - simctl_path=simctl_path, - udid=simulator_udid, - ) - root_dir = os.path.dirname(application_output_path) - register_dsyms(root_dir) - with extracted_app(application_output_path, app_name) as app_path: - logger.info("Will use simulator: %s", simulator_udid) - logger.info( - "Terminating any existing instances of the app in that simulator..." - ) - # First, quietly kill any existing instances of the app - app_bundle_id = bundle_id(app_path) - subprocess.run( - [simctl_path, "terminate", simulator_udid, app_bundle_id], - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - ) - logger.info("Installing...") - subprocess.run( - [simctl_path, "install", simulator_udid, app_path], check=True - ) - logger.info( - "Launching..." - ) - args = [ - simctl_path, - "launch", - ] - # Append optional launch arguments. - args.extend(sys.argv[1:]) - args.extend([ - simulator_udid, - app_bundle_id, - ]) - subprocess.run(args, env=simctl_launch_environ(), check=True) - - -def main( - *, - app_name: str, - application_output_path: str, - minimum_os: str, - platform_type: str, - sim_device: str, - sim_os_version: str, -): - """Main entry point to `bazel run` for *_application() targets. - - Args: - app_name: The name of the application (e.g. "Foo" for "Foo.app"). - application_output_path: Path to the output of an *_application(). - minimum_os: The minimum OS version required by the *_application() target. - platform_type: The Apple platform type for the given *_application() target. - sim_device: The name of the device (e.g. "iPhone 8 Plus"). - sim_os_version: The version of the Apple platform runtime (e.g. "13.2"). - """ - xcode_select_result = subprocess.run( - ["xcode-select", "-p"], - encoding="utf-8", - check=True, - stdout=subprocess.PIPE, - ) - developer_path = xcode_select_result.stdout.rstrip() - simctl_path = os.path.join(developer_path, "usr", "bin", "simctl") - - with apple_simulator( - platform_type=platform_type, - simctl_path=simctl_path, - minimum_os=minimum_os, - sim_device=sim_device, - sim_os_version=sim_os_version, - ) as simulator_udid: - run_app_in_simulator( - simulator_udid=simulator_udid, - developer_path=developer_path, - simctl_path=simctl_path, - application_output_path=application_output_path, - app_name=app_name, - ) - - -if __name__ == "__main__": - main( - app_name="Telegram", - application_output_path="Telegram/Telegram.ipa", - minimum_os="13.0", - platform_type="ios", - sim_device="iPhone 16 Pro", - sim_os_version="26.0", - ) diff --git a/scripts/launch_and_debug.sh b/scripts/launch_and_debug.sh deleted file mode 100755 index 401c299fd4..0000000000 --- a/scripts/launch_and_debug.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/zsh - -set -e - -# We don't use bazelisk run because it does a bunch of things we don't want in this case. -# Instead, we have our own script for launching the simulator and lldb. -# Ideally we should upstream these changes back to rules_apple since they should be useful for everyone. - -echo "Building..." -./build-input/bazel-8.4.2-darwin-arm64 build Telegram/Telegram --announce_rc --features=swift.use_global_module_cache --verbose_failures --remote_cache_async --jobs=16 --define=buildNumber=10000 --define=telegramVersion=12.2.1 --disk_cache=/Users/ali/telegram-bazel-cache -c dbg --ios_multi_cpus=sim_arm64 --watchos_cpus=arm64_32 --features=swift.enable_batch_mode -chmod -R 777 ./bazel-bin/Telegram - -tmp_file=$(pwd)/bazel-bin/Telegram/pid.txt -rm ${tmp_file} > /dev/null 2>&1 || true -touch ${tmp_file} -cp ./scripts/Telegram ./bazel-bin/Telegram/Telegram - -pushd ./bazel-bin -python3 ./Telegram/Telegram --wait-for-debugger --stdout=$(tty) --stderr=$(tty) > ${tmp_file} -popd - -# Get pid from the tmp_file -echo "$(cat "${tmp_file}" | awk -F': ' '{print $2}')" > ${tmp_file} -# Ugly hack to remove the newline from the file -pid=$(tr -d '\n' < ${tmp_file}) -echo "Launched app's pid: ${pid}" - -xcode_path=$(xcode-select -p) -debugserver_path="${xcode_path}/../SharedFrameworks/LLDB.framework/Versions/A/Resources/debugserver" - -# Just for sanity, kill any other debugservers that might be running -pgrep -lfa Resources/debugserver | awk '{print $1}' | xargs kill -9 - -# Launch the debugserver. The output of this command will signal the IDE to launch the lldb extension, -# which is hardcoded to connect to port 6667. -${debugserver_path} "localhost:6667" --attach ${pid} - -# Kill the app when debugging ends, just like in Xcode. -kill -9 ${pid} > /dev/null 2>&1 || true \ No newline at end of file diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index eeef314da8..935aec0af7 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -818,7 +818,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { } assert(Queue.mainQueue().isCurrent()) - + self.setupHistoryNode() self.interactiveEmojisDisposable = (self.context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])