Skip to content

Commit 2ba7d6f

Browse files
authored
Merge pull request #8001 from kozlovsky/fix/cx_freeze_support
Fix `is_frozen`, `get_core_path()`, `get_gui_path()` when `cx_freeze` is used for building binaries
2 parents 30afec6 + 61c0c08 commit 2ba7d6f

File tree

12 files changed

+63
-47
lines changed

12 files changed

+63
-47
lines changed

src/tribler/core/components/libtorrent/download_manager/download_config.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
from tribler.core.components.libtorrent.settings import DownloadDefaultsSettings, get_default_download_dir
88
from tribler.core.components.libtorrent.utils.libtorrent_helper import libtorrent as lt
99
from tribler.core.exceptions import InvalidConfigException
10-
from tribler.core.utilities.install_dir import get_lib_path
10+
from tribler.core.utilities.install_dir import get_core_path
1111
from tribler.core.utilities.path_util import Path
1212
from tribler.core.utilities.utilities import bdecode_compat
1313

1414
SPEC_FILENAME = 'download_config.spec'
15-
CONFIG_SPEC_PATH = get_lib_path() / 'components/libtorrent/download_manager' / SPEC_FILENAME
15+
CONFIG_SPEC_PATH = get_core_path() / 'components/libtorrent/download_manager' / SPEC_FILENAME
1616
NONPERSISTENT_DEFAULTS = {}
1717

1818

src/tribler/core/components/metadata_store/category_filter/category.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99

1010
from tribler.core.components.metadata_store.category_filter.family_filter import default_xxx_filter
1111
from tribler.core.components.metadata_store.category_filter.init_category import getCategoryInfo
12-
from tribler.core.utilities.install_dir import get_lib_path
12+
from tribler.core.utilities.install_dir import get_core_path
1313
from tribler.core.utilities.unicode import recursive_unicode
1414

15-
CATEGORY_CONFIG_FILE = get_lib_path() / 'components/metadata_store/category_filter/category.conf'
15+
CATEGORY_CONFIG_FILE = get_core_path() / 'components/metadata_store/category_filter/category.conf'
1616

1717

1818
def cmp_rank(a, b):

src/tribler/core/components/metadata_store/category_filter/family_filter.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
import logging
77
import re
88

9-
from tribler.core.utilities.install_dir import get_lib_path
9+
from tribler.core.utilities.install_dir import get_core_path
1010

1111
WORDS_REGEXP = re.compile('[a-zA-Z0-9]+')
1212

13-
termfilename = get_lib_path() / 'components' / 'metadata_store' / 'category_filter' / 'filter_terms.filter'
13+
termfilename = get_core_path() / 'components/metadata_store/category_filter/filter_terms.filter'
1414

1515

1616
def initTerms(filename):

src/tribler/core/components/metadata_store/category_filter/l2_filter.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import re
22

3-
from tribler.core.utilities.install_dir import get_lib_path
3+
from tribler.core.utilities.install_dir import get_core_path
44

55
# !ACHTUNG! We must first read the line into a file, then release the lock, and only then pass it to regex compiler.
66
# Otherwise, there is an annoying race condition that reads in an empty file!
7-
with open(get_lib_path() / 'components' / 'metadata_store' / 'category_filter' / 'level2.regex', encoding="utf-8") as f:
7+
with open(get_core_path() / 'components/metadata_store/category_filter/level2.regex', encoding="utf-8") as f:
88
regex = f.read().strip()
99
stoplist_expression = re.compile(regex, re.IGNORECASE)
1010

src/tribler/core/components/session.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from tribler.core.sentry_reporter.sentry_reporter import SentryReporter
1616
from tribler.core.utilities.async_group.async_group import AsyncGroup
1717
from tribler.core.utilities.crypto_patcher import patch_crypto_be_discovery
18-
from tribler.core.utilities.install_dir import get_lib_path
18+
from tribler.core.utilities.install_dir import get_core_path
1919
from tribler.core.utilities.network_utils import default_network_utils
2020
from tribler.core.utilities.notifier import Notifier
2121
from tribler.core.utilities.simpledefs import STATEDIR_CHANNELS_DIR, STATEDIR_DB_DIR
@@ -88,7 +88,7 @@ async def start_components(self):
8888
# On Mac, we bundle the root certificate for the SSL validation since Twisted is not using the root
8989
# certificates provided by the system trust store.
9090
if sys.platform == 'darwin':
91-
os.environ['SSL_CERT_FILE'] = str(get_lib_path() / 'root_certs_mac.pem')
91+
os.environ['SSL_CERT_FILE'] = str(get_core_path() / 'root_certs_mac.pem')
9292

9393
coros = [comp.start() for comp in self.components.values()]
9494
await gather(*coros, return_exceptions=not self.failfast)

src/tribler/core/logger/logger.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
import yaml
77

8+
from tribler.core.utilities.install_dir import get_core_path
9+
810
LOG_CONFIG_FILENAME = 'logger.yaml'
911

1012
logger = logging.getLogger(__name__)
@@ -37,11 +39,7 @@ def load_logger_config(app_mode, log_dir, current_process_is_primary=True):
3739

3840

3941
def get_logger_config_path():
40-
if not hasattr(sys, '_MEIPASS'):
41-
dirname = Path(__file__).absolute().parent
42-
else:
43-
dirname = Path(getattr(sys, '_MEIPASS')) / "tribler_source/tribler/core/logger"
44-
return dirname / LOG_CONFIG_FILENAME
42+
return get_core_path() / 'logger' / LOG_CONFIG_FILENAME
4543

4644

4745
def setup_logging(app_mode, log_dir: Path, config_path: Path):

src/tribler/core/logger/tests/test_logger.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
from io import BytesIO, TextIOWrapper
23
from unittest.mock import MagicMock, Mock, call, patch
34

@@ -6,15 +7,22 @@
67
from tribler.core.utilities.path_util import Path
78

89

9-
@patch('tribler.core.logger.logger.__file__', '/a/b/c/logger.py')
10+
@patch('tribler.core.__file__', 'xyz/tribler/core/__init__.py')
1011
def test_get_logger_config_path():
1112
config_path = get_logger_config_path()
1213
# take the last part of the path to ignore a drive name on Windows
13-
assert config_path.parts[-4:] == ('a', 'b', 'c', 'logger.yaml')
14+
assert config_path.parts[-4:] == ('tribler', 'core', 'logger', 'logger.yaml')
15+
16+
win_prefix = '//?/' if sys.platform.startswith('win') else '' # added by Path.fix_win_long_file in get_base_path
17+
18+
with patch('sys.frozen', True, create=True):
19+
with patch('sys.executable', '/a/b/c/tribler.exe', create=True):
20+
config_path = get_logger_config_path()
21+
assert config_path == Path(win_prefix + '/a/b/c/tribler_source/tribler/core/logger/logger.yaml')
1422

1523
with patch('sys._MEIPASS', '/x/y/z/', create=True):
1624
config_path = get_logger_config_path()
17-
assert config_path == Path('/x/y/z/tribler_source/tribler/core/logger/logger.yaml')
25+
assert config_path == Path(win_prefix + '/x/y/z/tribler_source/tribler/core/logger/logger.yaml')
1826

1927

2028
@patch('logging.basicConfig')

src/tribler/core/tests/test_configparser.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
from tribler.core.exceptions import OperationNotPossibleAtRuntimeException
66
from tribler.core.utilities.configparser import CallbackConfigParser
7-
from tribler.core.utilities.install_dir import get_lib_path
7+
from tribler.core.utilities.install_dir import get_core_path
88

9-
CONFIG_FILES_DIR = get_lib_path() / "tests/tools/data/config_files/"
9+
CONFIG_FILES_DIR = get_core_path() / "tests/tools/data/config_files/"
1010

1111

1212
def test_configparser_config1():

src/tribler/core/utilities/install_dir.py

+10-7
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,27 @@
55
"""
66
import sys
77

8-
import tribler.core
8+
import tribler
99
from tribler.core.utilities.path_util import Path
1010
from tribler.core.utilities.utilities import is_frozen
1111

1212

1313
def get_base_path():
14-
""" Get absolute path to resource, works for dev and for PyInstaller """
14+
""" Get absolute path to resource, works for dev and for PyInstaller/cx_freeze"""
1515
try:
1616
# PyInstaller creates a temp folder and stores path in _MEIPASS
17-
base_path = Path(sys._MEIPASS)
18-
except Exception:
19-
base_path = Path(tribler.core.__file__).parent
17+
base_path = Path(getattr(sys, '_MEIPASS'))
18+
except AttributeError:
19+
if getattr(sys, 'frozen', False): # cx_freeze
20+
base_path = Path(sys.executable).parent
21+
else:
22+
base_path = Path(tribler.__file__).parent
2023

2124
fixed_filename = Path.fix_win_long_file(base_path)
2225
return Path(fixed_filename)
2326

2427

25-
def get_lib_path():
28+
def get_core_path():
2629
if is_frozen():
2730
return get_base_path() / 'tribler_source/tribler/core'
28-
return get_base_path()
31+
return get_base_path() / 'core'

src/tribler/core/utilities/utilities.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,13 @@ def is_frozen():
195195
"""
196196
Return whether we are running in a frozen environment
197197
"""
198-
try:
199-
# PyInstaller creates a temp folder and stores path in _MEIPASS
200-
sys._MEIPASS # pylint: disable=protected-access
201-
except Exception: # pylint: disable=broad-except
202-
return False
203-
return True
198+
if hasattr(sys, '_MEIPASS'):
199+
return True # PyInstaller creates a temp folder and stores path in _MEIPASS
200+
201+
if getattr(sys, 'frozen', False):
202+
return True # cx_freeze creates 'frozen' attribute
203+
204+
return False
204205

205206

206207
fts_query_re = re.compile(r'\w+', re.UNICODE)

src/tribler/gui/start_gui.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,16 @@
1515
from tribler.core.logger.logger import load_logger_config
1616
from tribler.core.sentry_reporter.sentry_reporter import SentryStrategy
1717
from tribler.core.utilities.exit_codes import EXITCODE_ANOTHER_GUI_PROCESS_IS_RUNNING
18+
from tribler.core.utilities.install_dir import get_base_path, get_core_path
1819
from tribler.core.utilities.process_locking import GUI_LOCK_FILENAME, try_acquire_file_lock
1920
from tribler.core.utilities.process_manager import ProcessKind
2021
from tribler.core.utilities.process_manager.manager import setup_process_manager
21-
from tribler.core.utilities.utilities import show_system_popup
22+
from tribler.core.utilities.utilities import is_frozen, show_system_popup
2223
from tribler.gui import gui_sentry_reporter
2324
from tribler.gui.app_manager import AppManager
2425
from tribler.gui.tribler_app import TriblerApplication
2526
from tribler.gui.tribler_window import TriblerWindow
26-
from tribler.gui.utilities import get_translator
27+
from tribler.gui.utilities import get_translator, get_gui_path
2728

2829
logger = logging.getLogger(__name__)
2930

@@ -47,6 +48,12 @@ def run_gui(api_port: Optional[int], api_key: Optional[str], root_state_dir: Pat
4748

4849
load_logger_config('tribler-gui', root_state_dir, current_process_owns_lock)
4950

51+
logger.info(f"Root state dir: {root_state_dir}")
52+
logger.info(f"is_frozen: {is_frozen()}")
53+
logger.info(f"Base path: {get_base_path()}")
54+
logger.info(f"Core path: {get_core_path()}")
55+
logger.info(f"GUI path: {get_gui_path()}")
56+
5057
# Enable tracer using commandline args: --trace-debug or --trace-exceptions
5158
trace_logger = check_and_enable_code_tracing('gui', root_state_dir)
5259

src/tribler/gui/utilities.py

+11-12
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727

2828
import tribler.gui
2929
from tribler.core.components.knowledge.db.knowledge_db import ResourceType
30+
from tribler.core.utilities.install_dir import get_base_path
31+
from tribler.core.utilities.utilities import is_frozen
3032
from tribler.gui.defs import CORRUPTED_DB_WAS_FIXED_MESSAGE, HEALTH_DEAD, HEALTH_GOOD, HEALTH_MOOT, HEALTH_UNCHECKED
3133

3234
# fmt: off
@@ -194,17 +196,14 @@ def duration_to_string(seconds):
194196
return tr("%(seconds)is") % data
195197

196198

197-
def get_base_path():
198-
""" Get absolute path to resource, works for dev and for PyInstaller """
199-
try:
200-
# PyInstaller creates a temp folder and stores path in _MEIPASS
201-
base_path = sys._MEIPASS
202-
except Exception:
203-
base_path = os.path.dirname(tribler.gui.__file__)
204-
return base_path
199+
def get_gui_path():
200+
""" Get absolute path to resource, works for dev and for PyInstaller/cx_freeze"""
201+
if is_frozen():
202+
return get_base_path() / 'tribler_source/tribler/gui'
203+
return get_base_path() / 'gui'
205204

206205

207-
TRANSLATIONS_DIR = os.path.join(get_base_path(), "i18n")
206+
TRANSLATIONS_DIR = os.path.join(get_gui_path(), "i18n")
208207

209208

210209
def get_available_translations():
@@ -224,7 +223,7 @@ def get_available_translations():
224223

225224

226225
def get_ui_file_path(filename):
227-
return os.path.join(get_base_path(), 'qt_resources', filename)
226+
return os.path.join(get_gui_path(), 'qt_resources', filename)
228227

229228

230229
def get_image_path(filename: str, convert_slashes_to_forward: bool = False) -> str:
@@ -235,7 +234,7 @@ def get_image_path(filename: str, convert_slashes_to_forward: bool = False) -> s
235234
This can be used to ensure that images on Windows can be correctly loaded.
236235
Also see https://stackoverflow.com/questions/26121737/qt-stylesheet-background-image-from-filepath.
237236
"""
238-
path = os.path.join(get_base_path(), 'images', filename)
237+
path = os.path.join(get_gui_path(), 'images', filename)
239238
if convert_slashes_to_forward:
240239
path = path.replace("\\", "/")
241240
return path
@@ -245,7 +244,7 @@ def get_font_path(filename: str) -> str:
245244
"""
246245
Return a path to a particular font in the fonts directory.
247246
"""
248-
return os.path.join(get_base_path(), 'fonts', filename)
247+
return os.path.join(get_gui_path(), 'fonts', filename)
249248

250249

251250
def get_gui_setting(gui_settings, value, default, is_bool=False):

0 commit comments

Comments
 (0)