Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 15 additions & 37 deletions mytonctrl/mytonctrl.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,14 @@
from mytonctrl.console_cmd import add_command, check_usage_one_arg, check_usage_args_min_max_len
from mytonctrl.migrate import run_migrations
from mytonctrl.utils import GetItemFromList, timestamp2utcdatetime, fix_git_config, is_hex, GetColorInt, \
pop_user_from_args, pop_arg_from_args
pop_user_from_args, pop_arg_from_args, get_clang_major_version, get_os_version
from mytoninstaller.archive_blocks import download_blocks
from mytoninstaller.utils import get_ton_storage_port


CLANG_VERSION_REQUIRED = 21


def Init(local, ton, console, argv):
# Load translate table
with get_package_resource_path('mytonctrl', 'resources/translate.json') as translate_path:
Expand Down Expand Up @@ -370,8 +373,8 @@ def Upgrade(local, ton, args: list):
ton.SetSettings("validatorConsole", validatorConsole)

clang_version = get_clang_major_version()
if clang_version is None or clang_version < 16:
text = f"{{red}}WARNING: THIS UPGRADE WILL MOST PROBABLY FAIL DUE TO A WRONG CLANG VERSION: {clang_version}, REQUIRED VERSION IS 16. RECOMMENDED TO EXIT NOW AND UPGRADE CLANG AS PER INSTRUCTIONS: https://gist.github.com/neodix42/e4b1b68d2d5dd3dec75b5221657f05d7{{endc}}\n"
if clang_version is None or clang_version < CLANG_VERSION_REQUIRED:
text = f"{{red}}WARNING: THIS UPGRADE WILL MOST PROBABLY FAIL DUE TO A WRONG CLANG VERSION: {clang_version}, REQUIRED VERSION IS {CLANG_VERSION_REQUIRED}. RECOMMENDED TO EXIT NOW AND UPGRADE CLANG AS PER INSTRUCTIONS: https://gist.github.com/neodix42/24d6a401e928f7e895fcc8e7b7c5c24a{{endc}}\n"
color_print(text)
if input("Continue with upgrade anyway? [Y/n]\n").strip().lower() not in ('y', ''):
print('aborted.')
Expand Down Expand Up @@ -400,37 +403,6 @@ def upgrade_btc_teleport(local, ton, reinstall=False, branch: str = 'master', us
local.try_function(module.init, args=[reinstall, branch, user])


def get_clang_major_version():
try:
process = subprocess.run(["clang", "--version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
text=True, timeout=3)
if process.returncode != 0:
return None

output = process.stdout

lines = output.strip().split('\n')
if not lines:
return None

first_line = lines[0]
if "clang version" not in first_line:
return None

version_part = first_line.split("clang version")[1].strip()
major_version = version_part.split('.')[0]

major_version = ''.join(c for c in major_version if c.isdigit())

if not major_version:
return None

return int(major_version)
except Exception as e:
print(f"Error checking clang version: {type(e)}: {e}")
return None


def rollback_to_mtc1(local, ton, args):
color_print("{red}Warning: this is dangerous, please make sure you've backed up mytoncore's db.{endc}")
a = input("Do you want to continue? [Y/n]\n")
Expand Down Expand Up @@ -555,16 +527,22 @@ def check_adnl(local, ton):
print_warning(local, error)
#end define

def warnings(local, ton):
def check_ubuntu_version(local: MyPyClass):
distro, ver = get_os_version()
if distro == 'ubuntu':
if ver not in ['22.04', '24.04']:
warning = local.translate("ubuntu_version_warning").format(ver)
print_warning(local, warning)
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'check_ubuntu_version' function is missing an #end define comment that is used consistently throughout the rest of the file. For consistency, it should be added.

Suggested change
print_warning(local, warning)
print_warning(local, warning)
#end define

Copilot uses AI. Check for mistakes.

def warnings(local: MyPyClass, ton: MyTonCore):
local.try_function(check_disk_usage, args=[local, ton])
local.try_function(check_sync, args=[local, ton])
local.try_function(check_adnl, args=[local, ton])
local.try_function(check_validator_balance, args=[local, ton])
local.try_function(check_vps, args=[local, ton])
local.try_function(check_tg_channel, args=[local, ton])
local.try_function(check_slashed, args=[local, ton])
#end define

local.try_function(check_ubuntu_version, args=[local])
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'warnings' function is missing an #end define comment that is used consistently throughout the rest of the file. For consistency, it should be added.

Suggested change
local.try_function(check_ubuntu_version, args=[local])
local.try_function(check_ubuntu_version, args=[local])
#end define

Copilot uses AI. Check for mistakes.

def CheckTonUpdate(local):
git_path = "/usr/src/ton"
Expand Down
5 changes: 5 additions & 0 deletions mytonctrl/resources/translate.json
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,11 @@
"ru": "{{red}}Вы были оштрафованы на {0} TON за низкую эффективность в предыдущем раунде.{{endc}}",
"zh_TW": "{{red}}您因上一輪效率低而被罰款 {0} TON。{{endc}}"
},
"ubuntu_version_warning": {
"en": "{{red}}Ubuntu version must be 22.04 or 24.04. Found {0}. {{endc}}",
"ru": "{{red}}Версия Ubuntu должна быть 22.04 или 24.04. Найдена {0}. {{endc}}",
"zh_TW": "{{red}}Ubuntu 版本必須是 22.04 或 24.04。找到 {0}。{{endc}}"
},
"add_custom_overlay_cmd": {
"en": "Add custom overlay",
"ru": "Добавить пользовательский оверлей",
Expand Down
55 changes: 55 additions & 0 deletions mytonctrl/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,58 @@ def pop_arg_from_args(args: typing.List[str], arg_name: str) -> typing.Optional[

def pop_user_from_args(args: list) -> typing.Optional[str]:
return pop_arg_from_args(args, '-u')


def get_clang_major_version():
try:
process = subprocess.run(["clang", "--version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
text=True, timeout=3)
if process.returncode != 0:
return None

output = process.stdout

lines = output.strip().split('\n')
if not lines:
return None

first_line = lines[0]
if "clang version" not in first_line:
return None

version_part = first_line.split("clang version")[1].strip()
major_version = version_part.split('.')[0]

major_version = ''.join(c for c in major_version if c.isdigit())

if not major_version:
return None

return int(major_version)
except Exception as e:
print(f"Error checking clang version: {type(e)}: {e}")
return None


def get_os_version() -> typing.Tuple[typing.Optional[str], typing.Optional[str]]:
os_release_path = "/etc/os-release"

if not os.path.exists(os_release_path):
return None, None

data: typing.Dict[str, str] = {}
with open(os_release_path) as f:
for line in f:
if "=" not in line:
continue
key, val = line.strip().split("=", 1)
data[key] = val.strip('"')

distro = data.get("ID")
version = (
data.get("VERSION_ID")
or data.get("BUILD_ID")
or data.get("VERSION")
)

return distro, version
17 changes: 12 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,16 @@ def execute(self, command: str, no_color: bool = False) -> str:
...


class MyMyPyConsole(MyPyConsole):
class TestMyPyConsole(MyPyConsole):

def run_pre_up(self, no_color: bool = False):
output = io.StringIO()
with redirect_stderr(output), redirect_stdout(output):
self.startFunction()
output = output.getvalue()
if no_color:
output = remove_colors(output)
return output

def execute(self, command: str, no_color: bool = False) -> str:
output = io.StringIO()
Expand All @@ -98,15 +107,13 @@ def execute(self, command: str, no_color: bool = False) -> str:


@pytest.fixture()
def cli(local, ton) -> ConsoleProtocol:
console = MyMyPyConsole()
console.start_function = None # todo: do not forget about start function
def cli(local, ton) -> TestMyPyConsole:
console = TestMyPyConsole()
mp = pytest.MonkeyPatch()
mp.setattr(MyTonCore, "using_pool", lambda self: True)
mp.setattr(MyTonCore, "using_nominator_pool", lambda self: True)
mp.setattr(MyTonCore, "using_single_nominator", lambda self: True)
Init(local, ton, console, argv=[])
mp.undo()
console.debug = True
# console.Run()
return console
8 changes: 4 additions & 4 deletions tests/integration/test_basic_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def fake_run_as_root(run_args):
return 0

monkeypatch.setattr(mytonctrl_module, "run_as_root", fake_run_as_root)
monkeypatch.setattr(mytonctrl_module, "get_clang_major_version", lambda: 16)
monkeypatch.setattr(mytonctrl_module, "get_clang_major_version", lambda: 21)
monkeypatch.setattr(MyTonCore, "using_validator", lambda self: False)
with get_package_resource_path('mytonctrl', 'scripts/upgrade.sh') as upg_path:
assert upg_path.is_file()
Expand All @@ -98,15 +98,15 @@ def fake_SetSettings(self, name, value):
assert captured_settings["liteClient"]["liteServer"]["pubkeyPath"] == "/var/ton-work/keys/liteserver.pub"
assert calls["run_args"] == ["bash", upg_path, "-a", "author", "-r", "repo", "-b", "branch"]

# clang version is < 16, abort
# clang version is < 21, abort
calls = {}
monkeypatch.setattr(mytonctrl_module, "get_clang_major_version", lambda: 14)
monkeypatch.setattr('builtins.input', lambda _: "n")
output = cli.execute("upgrade")
assert "aborted." in output
assert not calls

# clang version is < 16, proceed
# clang version is < 21, proceed
monkeypatch.setattr(mytonctrl_module, "get_clang_major_version", lambda: 14)
monkeypatch.setattr('builtins.input', lambda _: "y")
output = cli.execute("upgrade")
Expand All @@ -115,7 +115,7 @@ def fake_SetSettings(self, name, value):
assert calls["run_args"] == ["bash", upg_path, "-a", "author", "-r", "repo", "-b", "branch"]

# call upgrade_btc_teleport if using validator
monkeypatch.setattr(mytonctrl_module, "get_clang_major_version", lambda: 16)
monkeypatch.setattr(mytonctrl_module, "get_clang_major_version", lambda: 21)
calls = {}
monkeypatch.setattr(MyTonCore, "using_validator", lambda self: True)
teleport_calls = {}
Expand Down
67 changes: 67 additions & 0 deletions tests/integration/test_preup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from pytest_mock import MockerFixture

from mytonctrl import mytonctrl


def test_warnings(cli, monkeypatch, mocker: MockerFixture):
monkeypatch.setattr(mytonctrl, 'CheckMytonctrlUpdate', lambda *_: None)
monkeypatch.setattr(mytonctrl, 'check_installer_user', lambda *_: None)
monkeypatch.setattr(mytonctrl, 'check_vport', lambda *_: None)

# test check_ubuntu_version

monkeypatch.setattr(mytonctrl.os.path, 'exists', lambda _: True)
res = '''
PRETTY_NAME="Ubuntu 22.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.4 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
'''
mock = mocker.mock_open(read_data=res)
monkeypatch.setattr('builtins.open', mock)
output = cli.run_pre_up()
assert 'Ubuntu' not in output

monkeypatch.setattr(mytonctrl.os.path, 'exists', lambda _: True)
res = '''
PRETTY_NAME="Ubuntu 24.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.3 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
'''
mock = mocker.mock_open(read_data=res)
monkeypatch.setattr('builtins.open', mock)
output = cli.run_pre_up()
assert 'Ubuntu' not in output

res = '''
PRETTY_NAME="Ubuntu 20.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="20.04"
VERSION="20.04.4 LTS (Focal Fossa)"
VERSION_CODENAME=focal
ID=ubuntu
'''
mock = mocker.mock_open(read_data=res)
monkeypatch.setattr('builtins.open', mock)
output = cli.run_pre_up()
assert 'Ubuntu version must be 22.04 or 24.04. Found 20.04.' in output

res = '''
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
'''
mock = mocker.mock_open(read_data=res)
monkeypatch.setattr('builtins.open', mock)
output = cli.run_pre_up()
assert 'Ubuntu' not in output

# todo: other warnings