Skip to content

Commit

Permalink
Merge pull request #2 from AntaresSimulatorTeam/fix/bug-on-windows
Browse files Browse the repository at this point in the history
fix(gui.windows): fix shortcut not created
  • Loading branch information
maugde authored Sep 12, 2024
2 parents e334bb7 + 9dd8557 commit 2b18254
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 80 deletions.
100 changes: 57 additions & 43 deletions src/antares_web_installer/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,28 @@
from pathlib import Path
from shutil import copy2, copytree

import httpx

if os.name == "nt":
from pythoncom import com_error

import httpx
import psutil

from antares_web_installer import logger
from antares_web_installer.config import update_config
from antares_web_installer.shortcuts import create_shortcut, get_desktop

# List of files and directories to exclude during installation
COMMON_EXCLUDED_FILES = {"config.prod.yaml", "config.yaml", "examples", "logs", "matrices", "tmp"}
COMMON_EXCLUDED_FILES = {"config.prod.yaml", "config.yaml", "examples", "logs", "matrices", "tmp", "*.zip"}
POSIX_EXCLUDED_FILES = COMMON_EXCLUDED_FILES | {"AntaresWebWorker"}
WINDOWS_EXCLUDED_FILES = COMMON_EXCLUDED_FILES | {"AntaresWebWorker.exe"}
EXCLUDED_FILES = POSIX_EXCLUDED_FILES if os.name == "posix" else WINDOWS_EXCLUDED_FILES

SERVER_NAMES = {"posix": "AntaresWebServer", "nt": "AntaresWebServer.exe"}
SHORTCUT_NAMES = {"posix": "AntaresWebServer.desktop", "nt": "AntaresWebServer.lnk"}

SERVER_ADDRESS = "http://127.0.0.1:8080"


class InstallError(Exception):
"""
Expand All @@ -46,7 +49,7 @@ class App:
server_path: Path = dataclasses.field(init=False)
progress: float = dataclasses.field(init=False)
nb_steps: int = dataclasses.field(init=False)
completed_step: int = dataclasses.field(init=False)
version: str = dataclasses.field(init=False)

def __post_init__(self):
# Prepare the path to the executable which is located in the target directory
Expand Down Expand Up @@ -74,10 +77,14 @@ def run(self) -> None:
self.current_step += 1

if self.launch:
self.start_server()
self.current_step += 1
self.open_browser()
self.current_step += 1
try:
self.start_server()
except InstallError as e:
raise e
else:
self.current_step += 1
self.open_browser()
self.current_step += 1

def update_progress(self, progress: float):
self.progress = (progress / self.nb_steps) + (self.current_step / self.nb_steps) * 100
Expand All @@ -95,6 +102,9 @@ def kill_running_server(self) -> None:
# evaluate matching between query process name and existing process name
try:
matching_ratio = SequenceMatcher(None, "antareswebserver", proc.name().lower()).ratio()
except FileNotFoundError:
logger.warning("The process '{}' does not exist anymore. Skipping its analysis".format(proc.name()))
continue
except psutil.NoSuchProcess:
logger.warning("The process '{}' was stopped before being analyzed. Skipping.".format(proc.name()))
continue
Expand Down Expand Up @@ -123,15 +133,15 @@ def install_files(self):
if self.target_dir.is_dir() and list(self.target_dir.iterdir()):
logger.info("Existing files were found. Proceed checking old version...")
# check app version
version = self.check_version()
logger.info(f"Old application version : {version}.")
old_version = self.check_version()
logger.info(f"Old application version : {old_version}.")
self.update_progress(25)

# update config file
logger.info("Update configuration file...")
src_config_path = self.source_dir.joinpath("config.yaml")
target_config_path = self.target_dir.joinpath("config.yaml")
update_config(src_config_path, target_config_path, version)
update_config(src_config_path, target_config_path, old_version)
logger.info("Configuration file updated.")
self.update_progress(50)

Expand All @@ -143,15 +153,16 @@ def install_files(self):

# check new version of the application
logger.info("Check new application version...")
version = self.check_version()
logger.info(f"New application version : {version}.")
self.version = self.check_version()
logger.info(f"New application version : {self.version}.")
self.update_progress(100)

else:
# copy all files from package
logger.info("No existing files found. Starting file copy...")
copytree(self.source_dir, self.target_dir, dirs_exist_ok=True)
logger.info("Files was successfully copied.")
self.version = self.check_version()
self.update_progress(100)

def copy_files(self):
Expand Down Expand Up @@ -217,17 +228,20 @@ def create_shortcuts(self):
Create a local server icon and a browser icon on desktop and
"""
# prepare a shortcut into the desktop directory
desktop_path = Path(get_desktop())

logger.info("Generating server shortcut on desktop...")
shortcut_name = SHORTCUT_NAMES[os.name]
shortcut_path = Path(get_desktop()).joinpath(shortcut_name)
name, ext = SHORTCUT_NAMES[os.name].split(".")
new_shortcut_name = f"{name}-{self.version}.{ext}"
shortcut_path = desktop_path.joinpath(new_shortcut_name)

# if the shortcut already exists, remove it
shortcut_path.unlink(missing_ok=True)
self.update_progress(50)

# shortcut generation
logger.info(
f"Shortcut will be created in {shortcut_path}, "
f"Shortcut {new_shortcut_name} will be created in {shortcut_path}, "
f"linked to '{self.server_path}' "
f"and located in '{self.target_dir}' directory."
)
Expand All @@ -242,66 +256,66 @@ def create_shortcuts(self):
except com_error as e:
raise InstallError("Impossible to create a new shortcut: {}\nSkip shortcut creation".format(e))
else:
logger.info("Server shortcut was successfully created.")
assert shortcut_path in list(desktop_path.iterdir())
logger.info(f"Server shortcut {shortcut_path} was successfully created.")
self.update_progress(100)

def start_server(self):
"""
Launch the local server as a background task
"""
logger.info("Attempt to start the newly installed server...")
args = [str(self.server_path)]
logger.info(f"Attempt to start the newly installed server located in '{self.target_dir}'...")
logger.debug(f"User permissions: {os.path.exists(self.server_path) and os.access(self.server_path, os.X_OK)}")

args = [self.server_path]
server_process = subprocess.Popen(
args=args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
shell=True,
cwd=self.target_dir,
shell=True,
)
self.update_progress(50)

if not server_process.poll():
logger.info("Server is starting up ...")
else:
logger.info(f"The server unexpectedly stopped running. (code {server_process.returncode})")
stdout, stderr = server_process.communicate()
msg = f"The server unexpectedly stopped running. (code {server_process.returncode})"
logger.info(msg)
logger.info(f"Server unexpectedly stopped.\nstdout: {stdout}\nstderr: {stderr}")
raise InstallError(msg)

nb_attempts = 0
max_attempts = 5
max_attempts = 10

while nb_attempts < max_attempts:
attempt_info = f"Attempt #{nb_attempts}: "
logger.info(f"Attempt #{nb_attempts}...")
try:
res = httpx.get("http://localhost:8080/", timeout=1)
except httpx.ConnectError:
logger.info(attempt_info + "The server is not accepting request yet. Retry ...")
except httpx.ConnectTimeout:
logger.info(attempt_info + "The server cannot retrieve a response yet. Retry ...")
else:
if res.status_code:
logger.info("Server is now available.")
self.update_progress(100)
logger.debug("Update progress was called.")
res = httpx.get(SERVER_ADDRESS + "/health", timeout=1)
if res.status_code == 200:
logger.info("The server is now running.")
break
finally:
nb_attempts += 1
if nb_attempts == max_attempts:
try:
server_process.wait(timeout=5)
except subprocess.TimeoutExpired as e:
raise InstallError(f"Impossible to launch Antares Web Server after {nb_attempts} attempts: {e}")
time.sleep(5)
except httpx.RequestError:
time.sleep(1)
nb_attempts += 1
else:
stdout, stderr = server_process.communicate()
msg = "The server didn't start in time"
logger.error(msg)
logger.error(f"stdout: {stdout}\nstderr: {stderr}")
raise InstallError(msg)

def open_browser(self):
"""
Open server URL in default user's browser
"""
logger.debug("In open browser method.")
url = "http://localhost:8080/"
try:
webbrowser.open(url=url, new=2)
webbrowser.open(url=SERVER_ADDRESS, new=2)
except webbrowser.Error as e:
raise InstallError(f"Could not open browser at '{url}': {e}") from e
raise InstallError(f"Could not open browser at '{SERVER_ADDRESS}': {e}") from e
else:
logger.info("Browser was successfully opened.")
self.update_progress(100)
18 changes: 18 additions & 0 deletions src/antares_web_installer/gui/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,18 +90,36 @@ def init_log_file_handler(self):

# initialize file handler logger
def init_console_handler(self, callback):
"""
@param callback:
@return:
"""
console_handler = ConsoleHandler(callback)
self.logger.addHandler(console_handler)

def init_progress_handler(self, callback):
"""
Initialize handler log of progress.
The logs generated will be shown on the window console during installation
@param callback: function that is used to update logs
"""
progress_logger = ProgressHandler(callback)
self.logger.addHandler(progress_logger)

def run(self) -> None:
"""
start program
@return:
"""
self.view.update_view()
super().run()

def install(self, callback: typing.Callable):
"""
Run App.install method
@param callback: function that is used to update logs
"""
self.init_log_file_handler()
self.logger.debug("file logger initialized.")
self.init_console_handler(callback)
Expand Down
9 changes: 7 additions & 2 deletions src/antares_web_installer/gui/widgets/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from antares_web_installer.shortcuts import get_homedir
from .button import CancelBtn, BackBtn, NextBtn, FinishBtn, InstallBtn
from ..mvc import ControllerError

if TYPE_CHECKING:
from antares_web_installer.gui.view import WizardView
Expand Down Expand Up @@ -152,8 +153,12 @@ def browse(self):
title="Choose the target directory",
initialdir=get_homedir(),
)
self.window.set_target_dir(dir_path)
self.target_path.set(dir_path)
try:
self.window.set_target_dir(dir_path)
except ControllerError:
pass
else:
self.target_path.set(dir_path)

def get_next_frame(self):
# Lazy import for typing and testing purposes
Expand Down
11 changes: 0 additions & 11 deletions src/antares_web_installer/shortcuts/_win32_shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,6 @@ def create_shortcut(
if isinstance(arguments, str):
arguments = [arguments] if arguments else []

target_parent, target_name = str(target).rsplit("\\", maxsplit=1)
new_target_name = "Antares Web Server.lnk"
new_target = os.path.join(target_parent, new_target_name)

# remove any existing shortcut
if os.path.exists(new_target):
os.remove(new_target)

wscript = _WSHELL.CreateShortCut(str(target))
wscript.TargetPath = str(exe_path)
wscript.Arguments = " ".join(arguments)
Expand All @@ -74,6 +66,3 @@ def create_shortcut(
if icon_path:
wscript.IconLocation = str(icon_path)
wscript.save()

# add spaces to shortcut name
os.rename(target, new_target)
Loading

0 comments on commit 2b18254

Please sign in to comment.