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
15 changes: 3 additions & 12 deletions .github/workflows/ci_cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:

- uses: pyansys/actions/tests-pytest@v4
with:
pytest-extra-args: "--cov=ansys --cov-report=term"
python-version: ${{ matrix.python-version }}

doc-build:
name: "Build documentation"
Expand Down Expand Up @@ -119,12 +119,7 @@ jobs:
run: pyinstaller frozen.spec

- name: Install NSIS
run: |
iwr -useb get.scoop.sh -outfile 'install.ps1'
.\install.ps1 -RunAsAdmin
scoop update
scoop bucket add extras
scoop install nsis
run: choco install nsis -y

- name: Print NSIS version
run: makensis -VERSION
Expand Down Expand Up @@ -159,12 +154,8 @@ jobs:
- name: Display structure of downloaded files
run: ls -R

- uses: montudor/action-zip@v1
with:
args: zip -qq -r python-installer-gui.zip installer

- name: "Release to GitHub"
uses: softprops/action-gh-release@v1
with:
files: python-installer-gui.zip
files: installer/*.exe
generate_release_notes: true
6 changes: 4 additions & 2 deletions frozen.spec
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ except NameError:

OUT_PATH = 'ansys_python_manager'
APP_NAME = 'Ansys Python Manager'
ASSETS_PATH = os.path.join(THIS_PATH, 'src/ansys/tools/installer/assets')
INSTALLER_PATH = os.path.join(THIS_PATH, 'src/ansys/tools/installer')
ASSETS_PATH = os.path.join(INSTALLER_PATH, 'assets')
ICON_FILE = os.path.join(ASSETS_PATH, 'pyansys_icon.ico')

# consider testing paths
Expand All @@ -28,13 +29,14 @@ added_files = [
(os.path.join(ASSETS_PATH, 'pyansys-light-crop.png'), 'assets'),
(os.path.join(ASSETS_PATH, 'ansys-favicon.png'), 'assets'),
(os.path.join(ASSETS_PATH, 'pyansys_icon.ico'), 'assets'),
(os.path.join(INSTALLER_PATH, 'VERSION'), '.'),
]

a = Analysis([main_py],
pathex=[],
binaries=[],
datas=added_files,
hiddenimports=[],
hiddenimports=['_cffi_backend'],
hookspath=[],
runtime_hooks=[],
excludes=[],
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ maintainers = [
{name = "PyAnsys Developers", email = "pyansys.maintainers@ansys.com"},
]
dependencies = [
"packaging",
"PyGitHub",
"appdirs",
"requests",
"PySide6",
Expand Down
62 changes: 47 additions & 15 deletions setup.nsi
Original file line number Diff line number Diff line change
@@ -1,47 +1,79 @@
; NSIS script for Ansys Python Manager installer


; Set the name, version, and output path of the installer
!define VERSION_FILE "src/ansys/tools/installer/VERSION"
!define PRODUCT_NAME "Ansys Python Manager"
!define PRODUCT_VERSION "0.1.0-beta0"
!define OUTFILE_NAME "Ansys Python Manager Setup-v${PRODUCT_VERSION}.exe"
!define /file PRODUCT_VERSION "src/ansys/tools/installer/VERSION"
!define OUTFILE_NAME "Ansys-Python-Manager-Setup-v${PRODUCT_VERSION}.exe"

Name "${PRODUCT_NAME}"
VIProductVersion "${PRODUCT_VERSION}"
OutFile "dist\${OUTFILE_NAME}"


!include "MUI2.nsh"
!include "InstallOptions.nsh"
!define MUI_PAGE_CUSTOMFUNCTION_PRE oneclickpre
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE oneclickleave
!insertmacro MUI_PAGE_INSTFILES
!include "uninstall.nsi"

; Define the installer sections
Section "Ansys Python Manager" SEC01
; Set the installation directory to the program files directory
SetOutPath "$PROGRAMFILES64\ANSYS Inc\Ansys Python Manager"

; Copy the files from the dist\ansys_python_manager directory
; File /r /oname=ignore "dist\ansys_python_manager\*"
File /r "dist\ansys_python_manager\*"

; Create the start menu directory
CreateDirectory "$SMPROGRAMS\Ansys Python Manager"

; Create the start menu shortcut
CreateShortCut "$SMPROGRAMS\Ansys Python Manager\Ansys Python Manager.lnk" "$INSTDIR\Ansys Python Manager.exe"

; Add the program to the installed programs list
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayName" "${PRODUCT_NAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayIcon" "$\"$INSTDIR\Ansys Python Manager.exe$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "Publisher" "ANSYS Inc"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "Version" "${PRODUCT_VERSION}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayVersion" "${PRODUCT_VERSION}"

WriteUninstaller "$INSTDIR\uninstall.exe"

; start after install
Exec "$INSTDIR\Ansys Python Manager.exe"

SectionEnd

; Define the uninstaller section
Section "Uninstall" SEC02
; Remove the installed files

Delete "$PROGRAMFILES64\Ansys Python Manager\*.*"
RMDir "$PROGRAMFILES64\Ansys Python Manager"

; Remove the registry keys
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Ansys Python Manager"

; Remove the start menu shortcut and directory
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
Delete "$SMPROGRAMS\Ansys Python Manager\Ansys Python Manager.lnk"
RMDir "$SMPROGRAMS\Ansys Python Manager"
SectionEnd

; Set the installer properties
Name "${PRODUCT_NAME}"
Icon "dist\ansys_python_manager\assets\pyansys_icon.ico"
InstallDir "$PROGRAMFILES64\ANSYS Inc\Ansys Python Manager"

; Simplify the installer GUI
; Define the custom functions for the MUI2 OneClick plugin
InstProgressFlags smooth
Function oneclickpre
!insertmacro MUI_HEADER_TEXT "Installing ${PRODUCT_NAME}" "Please wait while the installation completes."
; !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
HideWindow
FunctionEnd

Function oneclickleave
Quit
FunctionEnd

; Call the MUI2 OneClick plugin
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES

1 change: 1 addition & 0 deletions src/ansys/tools/installer/VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.1.0-beta1
38 changes: 21 additions & 17 deletions src/ansys/tools/installer/__init__.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
"""
Ansys Python Manager
"""

__version__ = "0.0.dev0"

import logging
import os
import sys
import warnings

from appdirs import user_cache_dir

from ansys.tools.installer.main import AnsysPythonInstaller, open_gui
if getattr(sys, "frozen", False):
# If the application is run as a bundle, the PyInstaller bootloader
# extends the sys module by a flag frozen=True and sets the app
# path into variable _MEIPASS'.
try:
_THIS_PATH = sys._MEIPASS
except:
# this might occur on a single file install
os.path.dirname(sys.executable)
else:
_THIS_PATH = os.path.dirname(os.path.abspath(__file__))

# Read in version programmatically from plain text
# this is done so NSIS can also link to the same version
with open(os.path.join(_THIS_PATH, "VERSION")) as fid:
__version__ = fid.read()

CACHE_DIR = user_cache_dir("ansys_python_installer")

Expand All @@ -23,16 +35,8 @@
warnings.warn(f"Unable create cache at {CACHE_DIR}. Using temporary directory")
CACHE_DIR = tempdir.gettempdir()

ENABLE_LOGGING = True
if ENABLE_LOGGING:
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

# Create a console handler that writes to stdout
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
console_handler.setFormatter(formatter)

# Add the console handler to the logger
logger.addHandler(console_handler)
try:
from ansys.tools.installer.main import open_gui # place this at end to allow import
except ModuleNotFoundError: # encountered during install
pass
2 changes: 1 addition & 1 deletion src/ansys/tools/installer/__main__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Main entrypoint for this module."""

from ansys.tools.installer import open_gui
from ansys.tools.installer.main import open_gui

if __name__ == "__main__":
open_gui()
45 changes: 45 additions & 0 deletions src/ansys/tools/installer/auto_updater.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""
Check for updates.
"""

from github import Github
from packaging import version

# Readonly on this repo
# This repository will be released to the public, there's no issue with this token.
# Exp Mon, Jan 1 2024, should be able to use public unauth by then
READ_ONLY_PAT = "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"


def query_gh_latest_release():
"""Check GitHub for updates.

Compares the current version with the version on GitHub.

Returns the version of the latest release and the download url of
the executable installer.

Returns
-------
str
Tag of the latest version.

str
Url of the latest release installer.

"""
gh = Github(READ_ONLY_PAT)
repo = gh.get_repo(f"pyansys/python-installer-qt-gui")

# Get the latest release and its tag name
latest_release = repo.get_latest_release()
latest_version_tag = latest_release.tag_name

download_asset = None
for asset in latest_release.get_assets():
if asset.name.endswith(".exe"):
download_asset = asset

download_url = None if download_asset is None else download_asset.url

return version.parse(latest_version_tag), download_url
38 changes: 38 additions & 0 deletions src/ansys/tools/installer/common.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
from functools import wraps
import logging
import sys
from threading import Thread
import traceback

LOG = logging.getLogger(__name__)
LOG.setLevel("DEBUG")


def threaded(fn):
Expand All @@ -10,3 +17,34 @@ def wrapper(*args, **kwargs):
return thread

return wrapper


def protected(fn):
"""Captures any exceptions from a function and passes it to the gui.

Attempts to display the error using ``show_error`` and protects
the main application from segmentation faulting.
"""

@wraps(fn)
def wrapper(*args, **kwargs):
self = args[0]
try:
return fn(*args, **kwargs)
except Exception as exception:
exc_info = sys.exc_info()
traceback.print_exception(*exc_info)
LOG.error(exception)
if hasattr(self, "exceptions"):
self._exceptions.append(exception)

# Visual error handing
if hasattr(self, "parent"):
if hasattr(self.parent, "show_error"):
self.parent.show_error(exception)
return wrapper

if hasattr(self, "_show_error"):
self._show_error(exception)

return wrapper
Loading