Skip to content

Commit

Permalink
refactor: improved implementation of shortcuts creation
Browse files Browse the repository at this point in the history
  • Loading branch information
laurent-laporte-pro committed Jun 11, 2024
1 parent 71b5d10 commit c295278
Showing 1 changed file with 94 additions and 77 deletions.
171 changes: 94 additions & 77 deletions src/antares_web_installer/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,25 @@
import textwrap
import time
import webbrowser
import psutil

from pathlib import Path
from importlib import resources
from shutil import copy2, copytree

import psutil

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

if os.name == 'nt':
from antares_web_installer.shortcuts import _win32_shell
logger = logging.getLogger(__name__)

# List of files and directories to exclude during installation
COMMON_EXCLUDED_FILES = {"config.prod.yaml", "config.yaml", "examples", "logs", "matrices", "tmp"}
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"}


class InstallError(Exception):
"""
Expand All @@ -39,19 +41,18 @@ class App:
launch: bool = False
browser: bool = False

logger = logging.getLogger(__name__)
target_file: Path = dataclasses.field(init=False)
server_path: Path = dataclasses.field(init=False)

def __post_init__(self):
self.target_file = self.target_dir.joinpath("AntaresWeb/AntaresWebServer")
if self.os_name == "nt":
self.target_file = self.target_file.with_suffix(".exe")
# Prepare the path to the executable which is located in the target directory
server_name = SERVER_NAMES[self.os_name]
self.server_path = self.target_dir.joinpath("AntaresWeb", server_name)

def run(self) -> None:
self.kill_running_server()
self.install_files()
if self.shortcut:
self.create_icons()
self.create_shortcuts()
if self.launch:
self.start_server()
if self.browser:
Expand All @@ -62,30 +63,31 @@ def kill_running_server(self) -> None:
Check whether Antares service is up.
Kill the process if so.
"""
server_name = SERVER_NAMES[self.os_name]
for proc in psutil.process_iter(["pid", "name"]):
if "antareswebserver" in proc.name().lower():
self.logger.info("Running server found. We will attempt to stop it.")
if server_name.lower() in proc.name().lower():
logger.info("Running server found. We will attempt to stop it.")

running_app = psutil.Process(pid=proc.pid)
running_app.kill()
running_app.wait(15)

self.logger.info("The application was successfully stopped.")
self.logger.info("No other processes found.")
logger.info("The application was successfully stopped.")

logger.info("No other processes found.")

def install_files(self):
"""
"""
""" """
# if the target directory already exists and isn't empty
if self.target_dir.is_dir() and list(self.target_dir.iterdir()):
# check app version
version = self.check_version()
self.logger.info(f"Old application version : {version}.")
logger.info(f"Old application version : {version}.")

# update config file
config_path = self.target_dir.joinpath("config.yaml")
update_config(config_path, config_path, version)
self.logger.info(f"New application version : {version}.")
logger.info(f"New application version : {version}.")

# copy binaries
self.copy_files()
Expand All @@ -105,11 +107,11 @@ def copy_files(self):
if elt_path.name not in EXCLUDED_FILES:
try:
if elt_path.is_file():
self.logger.info(f"'{elt_path}' file found and isn't an excluded file.")
logger.info(f"'{elt_path}' file found and isn't an excluded file.")
copy2(elt_path, self.target_dir)
else:
# copy new directory
self.logger.info(f"'{elt_path}' directory found and isn't an excluded directory.")
logger.info(f"'{elt_path}' directory found and isn't an excluded directory.")
copytree(elt_path, self.target_dir.joinpath(elt_path.name), dirs_exist_ok=True)

# handle permission errors
Expand All @@ -121,85 +123,100 @@ def check_version(self) -> str:
Execute command to get the current version of the server.
"""
# check user's os
if self.os_name.lower() == "posix": # if os is linux, remove ".exe"
exe_path = self.target_file.with_suffix("")
args = [str(self.target_file), "--version"]
args = [str(self.server_path), "--version"]

try:
self.logger.info(f"Attempt to get version of Antares server...")
logger.info("Attempt to get version of Antares server...")
version = subprocess.check_output(args, text=True, stderr=subprocess.PIPE).strip()
except FileNotFoundError as e:
raise InstallError(f"Can't check version: {e}") from e
except subprocess.CalledProcessError as e:
reason = textwrap.indent(e.stderr, " | ", predicate=lambda line: True)
raise InstallError(f"Can't check version:\n{reason}") from e

self.logger.info(f"Version found.")
logger.info("Version found.")
return version

def create_icons(self):
def create_shortcuts(self):
"""
Create a local server icon and a browser icon on desktop and
"""
# using pyshortcuts
self.logger.info("Generating server shortcut ...")

# if user's os is linux
if self.os_name.lower() == "posix":
self.logger.info("Unix os detected.")

# 1. create a .desktop
desktop_path = os.popen("xdg-user-dir DESKTOP").read().rstrip('\n')
shortcut_name = "AntaresWebServer.desktop"
shortcut_path = desktop_path + '/' + shortcut_name
os.popen(f"touch {shortcut_path}")

# 2. write the default desktop entry
with resources.path(
"antares_web_installer.assets.img",
"antares-web-installer-logo.png") as icon_path: # deprecated since 3.11 version
with open(shortcut_path, mode="w") as file:
content = (f"[Desktop Entry]\n"
f"Version=1.0\n"
f"Type=Application\n"
f"Terminal=true\n"
f"Exec={str(self.target_file.resolve().expanduser())}\n"
f"Name=Antares Web Server\n"
f"Comment=Launch Antares web server\n"
f"Icon={str(icon_path.resolve().expanduser())}")

file.write(content)

# 4. activate allow launching option
os.popen(f"chmod u+x {shortcut_path}")
self.logger.info("Execution rights were updated")

os.popen(f"gio set {shortcut_path} metadata::trusted true")
self.logger.info("Shortcut is now allowed to launch the server.")

# 5. Option add to application list
# os.popen(f"")

# 6. Option : add to path
# alias_command = f"alias AntaresWebServer=$PATH:{self.target_dir}\nalias antareswebserver=AntaresWebServer\n"
# os.popen(f"echo '{alias_command}' >> {shortcut_path}")

# otherwise, consider user's os is windows
else:
_win32_shell.create_shortcut(self.target_dir, self.target_file)
logger.info("Generating server shortcut...")

# prepare a shortcut into the desktop directory
shortcut_name = SHORTCUT_NAMES[self.os_name]
shortcut_path = Path(get_desktop()).joinpath(shortcut_name)

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

# create a new shortcut
create_shortcut(
shortcut_path,
exe_path=self.server_path,
working_dir=self.target_dir,
description="Launch Antares Web Server in background",
)

# # if user's os is linux
# if self.os_name.lower() == "posix":
# logger.info("Unix os detected.")
#
# # 1. create a .desktop
# desktop_path = os.popen("xdg-user-dir DESKTOP").read().rstrip("\n")
# shortcut_name = "AntaresWebServer.desktop"
# shortcut_path = desktop_path + "/" + shortcut_name
# os.popen(f"touch {shortcut_path}")
#
# # 2. write the default desktop entry
# with resources.path(
# "antares_web_installer.assets.img", "antares-web-installer-logo.png"
# ) as icon_path: # deprecated since 3.11 version
# with open(shortcut_path, mode="w") as file:
# content = (
# f"[Desktop Entry]\n"
# f"Version=1.0\n"
# f"Type=Application\n"
# f"Terminal=true\n"
# f"Exec={str(self.target_file.resolve().expanduser())}\n"
# f"Name=Antares Web Server\n"
# f"Comment=Launch Antares web server\n"
# f"Icon={str(icon_path.resolve().expanduser())}"
# )
#
# file.write(content)
#
# # 4. activate allow launching option
# os.popen(f"chmod u+x {shortcut_path}")
# logger.info("Execution rights were updated")
#
# os.popen(f"gio set {shortcut_path} metadata::trusted true")
# logger.info("Shortcut is now allowed to launch the server.")
#
# # 5. Option add to application list
# # os.popen(f"")
#
# # 6. Option : add to path
# # alias_command = f"alias AntaresWebServer=$PATH:{self.target_dir}\nalias antareswebserver=AntaresWebServer\n"
# # os.popen(f"echo '{alias_command}' >> {shortcut_path}")
#
# # otherwise, consider user's os is windows
# else:
# _win32_shell.create_shortcut(self.target_dir, self.target_file)

# test if it already exists
self.logger.info("Server shortcut was created.")
logger.info("Server shortcut was created.")

def start_server(self):
"""
Launch the local server as a background task
"""
args = [f"{self.target_file}"]
args = [str(self.server_path)]
server_process = subprocess.Popen(args=args, shell=True, start_new_session=True)
time.sleep(1.5) # wait for the server to complete startup
if server_process.poll() is None:
self.logger.info(f"Server was started successfully.")
logger.info("Server was started successfully.")

def open_browser(self):
"""
Expand All @@ -209,6 +226,6 @@ def open_browser(self):
try:
webbrowser.open(url=url, new=2)
except webbrowser.Error as e:
raise InstallError(f"Could not open browser at '{url}': {e}")
raise InstallError(f"Could not open browser at '{url}': {e}") from e
else:
self.logger.info(f"Browser was successfully opened at '{url}'.")
logger.info(f"Browser was successfully opened at '{url}'.")

0 comments on commit c295278

Please sign in to comment.