Skip to content

Commit

Permalink
Merge branch 'develop' into enhancement/2114/pathlib-handover
Browse files Browse the repository at this point in the history
  • Loading branch information
Rixxan authored Jul 22, 2024
2 parents da5d317 + ac9b7b4 commit 6139d66
Show file tree
Hide file tree
Showing 17 changed files with 445 additions and 121 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ build
dist.win32/
dist.*

# Ignore generated ChangeLog.html file
# Ignore generated ChangeLog files
ChangeLog.html
/scripts/script_output

# Ignore files
dump
Expand Down
12 changes: 12 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ This is the master changelog for Elite Dangerous Market Connector. Entries are
in the source (not distributed with the Windows installer) for the
currently used version.
---
Release 5.11.2
===

This release fixes a bug where minimizing to the system tray could cause the program to not un-minimize.

**Changes and Enhancements**
* Updated Translations
* Added a developer utility to help speed up changelog development

**Bug Fixes**
* Fixed a bug where minimizing to the system tray could cause the program to not un-minimize.

Release 5.11.1
===

Expand Down
10 changes: 3 additions & 7 deletions EDMCLogging.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
import logging.handlers
import os
import pathlib
import tempfile
import warnings
from contextlib import suppress
from fnmatch import fnmatch
Expand All @@ -52,9 +51,7 @@
from time import gmtime
from traceback import print_exc
from typing import TYPE_CHECKING, cast

import config as config_mod
from config import appcmdname, appname, config
from config import appcmdname, appname, config, trace_on

# TODO: Tests:
#
Expand Down Expand Up @@ -105,7 +102,7 @@


def _trace_if(self: logging.Logger, condition: str, message: str, *args, **kwargs) -> None:
if any(fnmatch(condition, p) for p in config_mod.trace_on):
if any(fnmatch(condition, p) for p in trace_on):
self._log(logging.TRACE, message, args, **kwargs) # type: ignore # we added it
return

Expand Down Expand Up @@ -185,8 +182,7 @@ def __init__(self, logger_name: str, loglevel: int | str = _default_loglevel):
# We want the files in %TEMP%\{appname}\ as {logger_name}-debug.log and
# rotated versions.
# This is {logger_name} so that EDMC.py logs to a different file.
logfile_rotating = pathlib.Path(tempfile.gettempdir())
logfile_rotating /= f'{appname}'
logfile_rotating = pathlib.Path(config.app_dir_path / 'logs')
logfile_rotating.mkdir(exist_ok=True)
logfile_rotating /= f'{logger_name}-debug.log'

Expand Down
31 changes: 23 additions & 8 deletions EDMarketConnector.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import sys
import threading
import webbrowser
import tempfile
from os import chdir, environ
from time import localtime, strftime, time
from typing import TYPE_CHECKING, Any, Literal
Expand All @@ -42,16 +41,19 @@
# not frozen.
chdir(pathlib.Path(__file__).parent)


# config will now cause an appname logger to be set up, so we need the
# console redirect before this
if __name__ == '__main__':
# Keep this as the very first code run to be as sure as possible of no
# output until after this redirect is done, if needed.
if getattr(sys, 'frozen', False):
from config import config
# By default py2exe tries to write log to dirname(sys.executable) which fails when installed
# unbuffered not allowed for text in python3, so use `1 for line buffering
log_file_path = pathlib.Path(tempfile.gettempdir()) / f'{appname}.log'
log_file_path = pathlib.Path(config.app_dir_path / 'logs')
log_file_path.mkdir(exist_ok=True)
log_file_path /= f'{appname}.log'

sys.stdout = sys.stderr = open(log_file_path, mode='wt', buffering=1) # Do NOT use WITH here.
# TODO: Test: Make *sure* this redirect is working, else py2exe is going to cause an exit popup

Expand Down Expand Up @@ -454,7 +456,7 @@ def __init__(self, master: tk.Tk): # noqa: C901, CCR001 # TODO - can possibly f
if sys.platform == 'win32':
from simplesystray import SysTrayIcon

def open_window(systray: 'SysTrayIcon') -> None:
def open_window(systray: 'SysTrayIcon', *args) -> None:
self.w.deiconify()

menu_options = (("Open", None, open_window),)
Expand Down Expand Up @@ -619,7 +621,7 @@ def open_window(systray: 'SysTrayIcon') -> None:
self.help_menu.add_command(command=lambda: self.updater.check_for_updates()) # Check for Updates...
# About E:D Market Connector
self.help_menu.add_command(command=lambda: not self.HelpAbout.showing and self.HelpAbout(self.w))
logfile_loc = pathlib.Path(tempfile.gettempdir()) / appname
logfile_loc = pathlib.Path(config.app_dir_path / 'logs')
self.help_menu.add_command(command=lambda: prefs.open_folder(logfile_loc)) # Open Log Folder
self.help_menu.add_command(command=lambda: prefs.help_open_system_profiler(self)) # Open Log Folde

Expand Down Expand Up @@ -845,9 +847,20 @@ def postprefs(self, dologin: bool = True, **postargs):
)
update_msg = update_msg.replace('\\n', '\n')
update_msg = update_msg.replace('\\r', '\r')
stable_popup = tk.messagebox.askyesno(title=title, message=update_msg, parent=postargs.get('Parent'))
stable_popup = tk.messagebox.askyesno(title=title, message=update_msg)
if stable_popup:
webbrowser.open("https://github.com/edCD/eDMarketConnector/releases/latest")
webbrowser.open("https://github.com/EDCD/eDMarketConnector/releases/latest")
if postargs.get('Restart_Req'):
# LANG: Text of Notification Popup for EDMC Restart
restart_msg = tr.tl('A restart of EDMC is required. EDMC will now restart.')
restart_box = tk.messagebox.Message(
title=tr.tl('Restart Required'), # LANG: Title of Notification Popup for EDMC Restart
message=restart_msg,
type=tk.messagebox.OK
)
restart_box.show()
if restart_box:
app.onexit(restart=True)

def set_labels(self):
"""Set main window labels, e.g. after language change."""
Expand Down Expand Up @@ -1851,7 +1864,7 @@ def exit_tray(self, systray: 'SysTrayIcon') -> None:
)
exit_thread.start()

def onexit(self, event=None) -> None:
def onexit(self, event=None, restart: bool = False) -> None:
"""Application shutdown procedure."""
if sys.platform == 'win32':
shutdown_thread = threading.Thread(
Expand Down Expand Up @@ -1914,6 +1927,8 @@ def onexit(self, event=None) -> None:
self.w.destroy()

logger.info('Done.')
if restart:
os.execv(sys.executable, ['python'] + sys.argv)

def drag_start(self, event) -> None:
"""Initiate dragging the window."""
Expand Down
17 changes: 14 additions & 3 deletions L10n/en.template
Original file line number Diff line number Diff line change
Expand Up @@ -468,8 +468,11 @@
/* prefs.py: Label for location of third-party plugins folder; In files: prefs.py:908; */
"Plugins folder" = "Plugins folder";

/* prefs.py: Label on button used to open a filesystem folder; In files: prefs.py:915; */
"Open" = "Open";
/* prefs.py: Label on button used to open the Plugin Folder; */
"Open Plugins Folder" = "Open Plugins Folder";

/* prefs.py: Selecting the Location of the Plugin Directory on the Filesystem; */
"Plugin Directory Location" = "Plugin Directory Location";

/* prefs.py: Tip/label about how to disable plugins; In files: prefs.py:923; */
"Tip: You can disable a plugin by{CR}adding '{EXT}' to its folder name" = "Tip: You can disable a plugin by{CR}adding '{EXT}' to its folder name";
Expand Down Expand Up @@ -804,12 +807,20 @@
/* EDMarketConnector.py: Inform the user the Update Track has changed; */
"Update Track Changed to {TRACK}" = "Update Track Changed to {TRACK}";


/* EDMarketConnector.py: Inform User of Beta -> Stable Transition Risks; */
"Update track changed to Stable from Beta. You will no longer receive Beta updates. You will stay on your current Beta version until the next Stable release.\r\n\r\nYou can manually revert to the latest Stable version. To do so, you must download and install the latest Stable version manually. Note that this may introduce bugs or break completely if downgrading between major versions with significant changes.\r\n\r\nDo you want to open GitHub to download the latest release?" = "Update track changed to Stable from Beta. You will no longer receive Beta updates. You will stay on your current Beta version until the next Stable release.\r\n\r\nYou can manually revert to the latest Stable version. To do so, you must download and install the latest Stable version manually. Note that this may introduce bugs or break completely if downgrading between major versions with significant changes.\r\n\r\nDo you want to open GitHub to download the latest release?";

/* EDMarketConnector.py: Title of Notification Popup for EDMC Restart; */
"Restart Required" = "Restart Required";

/* EDMarketConnector.py: Text of Notification Popup for EDMC Restart; */
"A restart of EDMC is required. EDMC will now restart." = "A restart of EDMC is required. EDMC will now restart.";

/* myNotebook.py: Can't Paste Images or Files in Text; */
"Cannot paste non-text content." = "Cannot paste non-text content.";

/* ttkHyperlinkLabel.py: Open Element In Selected Provider; */
"Open in {URL}" = "Open in {URL}";

/* ttkHyperlinkLabel.py: Copy the Inara SLEF Format of the active ship to the clipboard; */
"Copy Inara SLEF" = "Copy Inara SLEF";
8 changes: 7 additions & 1 deletion config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
# <https://semver.org/#semantic-versioning-specification-semver>
# Major.Minor.Patch(-prerelease)(+buildmetadata)
# NB: Do *not* import this, use the functions appversion() and appversion_nobuild()
_static_appversion = '5.11.1'
_static_appversion = '5.11.2'
_cached_version: semantic_version.Version | None = None
copyright = '© 2015-2019 Jonathan Harris, 2020-2024 EDCD'

Expand Down Expand Up @@ -189,6 +189,7 @@ class AbstractConfig(abc.ABC):

app_dir_path: pathlib.Path
plugin_dir_path: pathlib.Path
default_plugin_dir_path: pathlib.Path
internal_plugin_dir_path: pathlib.Path
respath_path: pathlib.Path
home_path: pathlib.Path
Expand Down Expand Up @@ -279,6 +280,11 @@ def plugin_dir(self) -> str:
"""Return a string version of plugin_dir."""
return str(self.plugin_dir_path)

@property
def default_plugin_dir(self) -> str:
"""Return a string version of plugin_dir."""
return str(self.default_plugin_dir_path)

@property
def internal_plugin_dir(self) -> str:
"""Return a string version of internal_plugin_dir."""
Expand Down
10 changes: 7 additions & 3 deletions config/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ def __init__(self, filename: str | None = None) -> None:
self.app_dir_path = xdg_data_home / appname
self.app_dir_path.mkdir(exist_ok=True, parents=True)

self.plugin_dir_path = self.app_dir_path / 'plugins'
self.plugin_dir_path.mkdir(exist_ok=True)

self.default_plugin_dir_path = self.app_dir_path / 'plugins'
self.respath_path = pathlib.Path(__file__).parent.parent

self.internal_plugin_dir_path = self.respath_path / 'plugins'
Expand Down Expand Up @@ -62,6 +60,12 @@ def __init__(self, filename: str | None = None) -> None:

self.config.add_section(self.SECTION)

if (plugdir_str := self.get_str('plugin_dir')) is None or not pathlib.Path(plugdir_str).is_dir():
self.set("plugin_dir", str(self.default_plugin_dir_path))
plugdir_str = self.default_plugin_dir
self.plugin_dir_path = pathlib.Path(plugdir_str)
self.plugin_dir_path.mkdir(exist_ok=True)

if (outdir := self.get_str('outdir')) is None or not pathlib.Path(outdir).is_dir():
self.set('outdir', self.home)

Expand Down
34 changes: 19 additions & 15 deletions config/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,28 @@ class WinConfig(AbstractConfig):

def __init__(self) -> None:
super().__init__()
REGISTRY_SUBKEY = r'Software\Marginal\EDMarketConnector' # noqa: N806
create_key_defaults = functools.partial(
winreg.CreateKeyEx,
key=winreg.HKEY_CURRENT_USER,
access=winreg.KEY_ALL_ACCESS | winreg.KEY_WOW64_64KEY,
)

try:
self.__reg_handle: winreg.HKEYType = create_key_defaults(sub_key=REGISTRY_SUBKEY)

except OSError:
logger.exception('Could not create required registry keys')
raise

self.app_dir_path = pathlib.Path(known_folder_path(FOLDERID_LocalAppData)) / appname # type: ignore
self.app_dir_path.mkdir(exist_ok=True)

self.plugin_dir_path = self.app_dir_path / 'plugins'
self.default_plugin_dir_path = self.app_dir_path / 'plugins'
if (plugdir_str := self.get_str('plugin_dir')) is None or not pathlib.Path(plugdir_str).is_dir():
self.set("plugin_dir", str(self.default_plugin_dir_path))
plugdir_str = self.default_plugin_dir
self.plugin_dir_path = pathlib.Path(plugdir_str)
self.plugin_dir_path.mkdir(exist_ok=True)

if getattr(sys, 'frozen', False):
Expand All @@ -68,20 +86,6 @@ def __init__(self) -> None:
known_folder_path(FOLDERID_SavedGames)) / 'Frontier Developments' / 'Elite Dangerous' # type: ignore
self.default_journal_dir_path = journal_dir_path if journal_dir_path.is_dir() else None # type: ignore

REGISTRY_SUBKEY = r'Software\Marginal\EDMarketConnector' # noqa: N806
create_key_defaults = functools.partial(
winreg.CreateKeyEx,
key=winreg.HKEY_CURRENT_USER,
access=winreg.KEY_ALL_ACCESS | winreg.KEY_WOW64_64KEY,
)

try:
self.__reg_handle: winreg.HKEYType = create_key_defaults(sub_key=REGISTRY_SUBKEY)

except OSError:
logger.exception('Could not create required registry keys')
raise

self.identifier = applongname
if (outdir_str := self.get_str('outdir')) is None or not pathlib.Path(outdir_str).is_dir():
docs = known_folder_path(FOLDERID_Documents)
Expand Down
3 changes: 2 additions & 1 deletion coriolis-update-files.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ def add(modules, name, attributes) -> None:
for m in list(data['Ships'].values()):
name = coriolis_ship_map.get(m['properties']['name'], str(m['properties']['name']))
assert name in reverse_ship_map, name
ships[name] = {'hullMass': m['properties']['hullMass']}
ships[name] = {'hullMass': m['properties']['hullMass'],
'reserveFuelCapacity': m['properties']['reserveFuelCapacity']}
for i, bulkhead in enumerate(bulkheads):
modules['_'.join([reverse_ship_map[name], 'armour', bulkhead])] = {'mass': m['bulkheads'][i]['mass']}

Expand Down
8 changes: 3 additions & 5 deletions debug_webserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,19 @@
import gzip
import json
import pathlib
import tempfile
import threading
import zlib
from http import server
from typing import Any, Callable, Literal
from urllib.parse import parse_qs

from config import appname
import config
from EDMCLogging import get_main_logger

logger = get_main_logger()

output_lock = threading.Lock()
output_data_path = pathlib.Path(tempfile.gettempdir()) / f'{appname}' / 'http_debug'
SAFE_TRANSLATE = str.maketrans({x: '_' for x in "!@#$%^&*()./\\\r\n[]-+='\";:?<>,~`"})
output_data_path = pathlib.Path(config.app_dir_path / 'logs' / 'http_debug')
SAFE_TRANSLATE = str.maketrans(dict.fromkeys("!@#$%^&*()./\\\r\n[]-+='\";:?<>,~`", '_'))


class LoggingHandler(server.BaseHTTPRequestHandler):
Expand Down
34 changes: 32 additions & 2 deletions monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@
from typing import TYPE_CHECKING, Any, BinaryIO, MutableMapping
import semantic_version
import util_ships
from config import config
from edmc_data import edmc_suit_shortnames, edmc_suit_symbol_localised
from config import config, appname, appversion
from edmc_data import edmc_suit_shortnames, edmc_suit_symbol_localised, ship_name_map
from EDMCLogging import get_main_logger
from edshipyard import ships

if TYPE_CHECKING:
import tkinter
Expand Down Expand Up @@ -108,6 +109,7 @@ def __init__(self) -> None:
self.group: str | None = None
self.cmdr: str | None = None
self.started: int | None = None # Timestamp of the LoadGame event
self.slef: str | None = None

self._navroute_retries_remaining = 0
self._last_navroute_journal_timestamp: float | None = None
Expand Down Expand Up @@ -701,6 +703,34 @@ def parse_entry(self, line: bytes) -> MutableMapping[str, Any]: # noqa: C901, C
module.pop('AmmoInHopper')

self.state['Modules'][module['Slot']] = module
# SLEF
initial_dict: dict[str, dict[str, Any]] = {
"header": {"appName": appname, "appVersion": str(appversion())}
}
data_dict = {}
for module in entry['Modules']:
if module.get('Slot') == 'FuelTank':
cap = module['Item'].split('size')
cap = cap[1].split('_')
cap = 2 ** int(cap[0])
ship = ship_name_map[entry["Ship"]]
fuel = {'Main': cap, 'Reserve': ships[ship]['reserveFuelCapacity']}
data_dict.update({"FuelCapacity": fuel})
data_dict.update({
'Ship': entry["Ship"],
'ShipName': entry['ShipName'],
'ShipIdent': entry['ShipIdent'],
'HullValue': entry['HullValue'],
'ModulesValue': entry['ModulesValue'],
'Rebuy': entry['Rebuy'],
'MaxJumpRange': entry['MaxJumpRange'],
'UnladenMass': entry['UnladenMass'],
'CargoCapacity': entry['CargoCapacity'],
'Modules': entry['Modules'],
})
initial_dict.update({'data': data_dict})
output = json.dumps(initial_dict, indent=4)
self.slef = str(f"[{output}]")

elif event_type == 'modulebuy':
self.state['Modules'][entry['Slot']] = {
Expand Down
Loading

0 comments on commit 6139d66

Please sign in to comment.