mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-07 13:41:15 -07:00
Update Windows updater
This commit is contained in:
parent
7f84353c69
commit
0d9c1c640e
3 changed files with 89 additions and 83 deletions
|
@ -76,9 +76,13 @@ InstallDir "$PROGRAMFILES\${APP_NAME}"
|
||||||
|
|
||||||
!include Sections.nsh
|
!include Sections.nsh
|
||||||
|
|
||||||
|
Var /GLOBAL norun
|
||||||
Var /GLOBAL nolaunch
|
Var /GLOBAL nolaunch
|
||||||
|
|
||||||
!include "MUI.nsh"
|
!include "MUI.nsh"
|
||||||
|
!include "FileFunc.nsh"
|
||||||
|
!insertmacro GetParameters
|
||||||
|
!insertmacro GetOptions
|
||||||
|
|
||||||
!define MUI_ABORTWARNING
|
!define MUI_ABORTWARNING
|
||||||
!define MUI_UNABORTWARNING
|
!define MUI_UNABORTWARNING
|
||||||
|
@ -125,6 +129,7 @@ File /nonfatal /a /r "..\dist\${APP_NAME}\"
|
||||||
|
|
||||||
nsExec::Exec '$SYSDIR\SCHTASKS /Create /TN TautulliUpdateTask /XML "$INSTDIR\TautulliUpdateTask.xml" /F'
|
nsExec::Exec '$SYSDIR\SCHTASKS /Create /TN TautulliUpdateTask /XML "$INSTDIR\TautulliUpdateTask.xml" /F'
|
||||||
|
|
||||||
|
StrCmp $norun 1 +3 0
|
||||||
IfSilent 0 +2
|
IfSilent 0 +2
|
||||||
ExecShell "" "$INSTDIR\${MAIN_APP_EXE}" $nolaunch
|
ExecShell "" "$INSTDIR\${MAIN_APP_EXE}" $nolaunch
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
@ -218,6 +223,12 @@ SectionEnd
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
Function .onInit
|
Function .onInit
|
||||||
|
StrCpy $norun 0
|
||||||
|
${GetParameters} $CMDLINE
|
||||||
|
${GetOptions} "$CMDLINE" "/NORUN" $R0
|
||||||
|
IfErrors +2 0
|
||||||
|
StrCpy $norun 1
|
||||||
|
|
||||||
IfSilent 0 +2
|
IfSilent 0 +2
|
||||||
StrCpy $nolaunch "--nolaunch"
|
StrCpy $nolaunch "--nolaunch"
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
apscheduler==3.6.3
|
apscheduler==3.6.3
|
||||||
|
psutil==5.8.0
|
||||||
pyinstaller==4.1
|
pyinstaller==4.1
|
||||||
pyopenssl==20.0.0
|
pyopenssl==20.0.0
|
||||||
pycryptodomex==3.9.9
|
pycryptodomex==3.9.9
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
from logging import handlers
|
from logging import handlers
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import psutil
|
||||||
import requests
|
import requests
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
@ -44,43 +45,47 @@ file_handler.setFormatter(file_formatter)
|
||||||
logger.addHandler(file_handler)
|
logger.addHandler(file_handler)
|
||||||
|
|
||||||
|
|
||||||
def kill_if_exists(process_name):
|
def read_file(file_path):
|
||||||
output = subprocess.check_output(
|
try:
|
||||||
['TASKLIST', '/FI', 'IMAGENAME eq {}'.format(process_name)],
|
with open(file_path, 'r') as f:
|
||||||
creationflags=CREATE_NO_WINDOW).decode()
|
return f.read().strip(' \n\r')
|
||||||
output = output.strip().split('\n')[-1]
|
except Exception as e:
|
||||||
if output.lower().startswith(process_name.lower()):
|
logger.error('Read file error: %s', e)
|
||||||
return subprocess.check_call(
|
raise Exception(1)
|
||||||
['TASKKILL', '/IM', process_name],
|
|
||||||
creationflags=CREATE_NO_WINDOW)
|
|
||||||
return 0
|
def request_json(url):
|
||||||
|
try:
|
||||||
|
response = requests.get(url)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error('Request error: %s', e)
|
||||||
|
raise Exception(2)
|
||||||
|
|
||||||
|
|
||||||
|
def kill_and_get_processes(process_name):
|
||||||
|
processes = []
|
||||||
|
for process in psutil.process_iter():
|
||||||
|
if process.name() == process_name:
|
||||||
|
processes.append(process.cmdline())
|
||||||
|
logger.info('Sending SIGTERM to %s (PID=%d)', process.name(), process.pid)
|
||||||
|
process.terminate()
|
||||||
|
return processes
|
||||||
|
|
||||||
|
|
||||||
def update_tautulli():
|
def update_tautulli():
|
||||||
logger.info('Starting Tautulli update check')
|
logger.info('Starting Tautulli update check')
|
||||||
|
|
||||||
with open(os.path.join(SCRIPT_PATH, 'branch.txt'), 'r') as f:
|
branch = read_file(os.path.join(SCRIPT_PATH, 'branch.txt'))
|
||||||
branch = f.read().strip(' \n\r')
|
|
||||||
logger.info('Branch: %s', branch)
|
logger.info('Branch: %s', branch)
|
||||||
|
|
||||||
with open(os.path.join(SCRIPT_PATH, 'version.txt'), 'r') as f:
|
current_version = read_file(os.path.join(SCRIPT_PATH, 'version.txt'))
|
||||||
current_version = f.read().strip(' \n\r')
|
|
||||||
logger.info('Current version: %s', current_version)
|
logger.info('Current version: %s', current_version)
|
||||||
|
|
||||||
logger.info('Retrieving latest version from GitHub')
|
logger.info('Retrieving latest version from GitHub')
|
||||||
try:
|
commits = request_json('{}/commits/{}'.format(REPO_URL, branch))
|
||||||
response = requests.get('{}/commits/{}'.format(REPO_URL, branch))
|
latest_version = commits['sha']
|
||||||
response.raise_for_status()
|
|
||||||
except Exception as e:
|
|
||||||
logger.error('Request error: %s', e)
|
|
||||||
return 2
|
|
||||||
|
|
||||||
try:
|
|
||||||
commits = response.json()
|
|
||||||
latest_version = commits['sha']
|
|
||||||
except Exception as e:
|
|
||||||
logger.error('Failed to retrieve latest version: %s', e)
|
|
||||||
return 1
|
|
||||||
logger.info('Latest version: %s', latest_version)
|
logger.info('Latest version: %s', latest_version)
|
||||||
|
|
||||||
if current_version == latest_version:
|
if current_version == latest_version:
|
||||||
|
@ -88,78 +93,67 @@ def update_tautulli():
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
logger.info('Comparing version on GitHub')
|
logger.info('Comparing version on GitHub')
|
||||||
try:
|
compare = request_json('{}/compare/{}...{}'.format(REPO_URL, latest_version, current_version))
|
||||||
response = requests.get('{}/compare/{}...{}'.format(REPO_URL, latest_version, current_version))
|
commits_behind = compare['behind_by']
|
||||||
response.raise_for_status()
|
|
||||||
except Exception as e:
|
|
||||||
logger.error('Request error: %s', e)
|
|
||||||
return 2
|
|
||||||
|
|
||||||
try:
|
|
||||||
compare = response.json()
|
|
||||||
commits_behind = compare['behind_by']
|
|
||||||
except Exception as e:
|
|
||||||
logger.error('Failed to compare commits: %s', e)
|
|
||||||
return 1
|
|
||||||
logger.info('Commits behind: %s', commits_behind)
|
logger.info('Commits behind: %s', commits_behind)
|
||||||
|
|
||||||
if commits_behind > 0:
|
if commits_behind <= 0:
|
||||||
logger.info('Retrieving releases on GitHub')
|
logger.info('Tautulli is already up to date')
|
||||||
try:
|
return 0
|
||||||
response = requests.get('{}/releases'.format(REPO_URL))
|
|
||||||
response.raise_for_status()
|
|
||||||
except Exception as e:
|
|
||||||
logger.error('Request error: %s', e)
|
|
||||||
return 2
|
|
||||||
|
|
||||||
try:
|
logger.info('Retrieving releases on GitHub')
|
||||||
releases = response.json()
|
releases = request_json('{}/releases'.format(REPO_URL))
|
||||||
|
|
||||||
if branch == 'master':
|
if branch == 'master':
|
||||||
release = next((r for r in releases if not r['prerelease']), releases[0])
|
release = next((r for r in releases if not r['prerelease']), releases[0])
|
||||||
else:
|
else:
|
||||||
release = next((r for r in releases), releases[0])
|
release = next((r for r in releases), releases[0])
|
||||||
|
|
||||||
version = release['tag_name']
|
version = release['tag_name']
|
||||||
asset = next((a for a in release['assets'] if a['content_type'] == 'application/vnd.microsoft.portable-executable'), None)
|
logger.info('Release: %s', version)
|
||||||
download_url = asset['browser_download_url']
|
|
||||||
download_file = asset['name']
|
|
||||||
except Exception as e:
|
|
||||||
logger.error('Failed to retrieve releases: %s', e)
|
|
||||||
return 1
|
|
||||||
logger.info('Release: %s', version)
|
|
||||||
|
|
||||||
file_path = os.path.join(tempfile.gettempdir(), download_file)
|
win_exe = 'application/vnd.microsoft.portable-executable'
|
||||||
logger.info('Downloading installer to temporary directory: %s', file_path)
|
asset = next((a for a in release['assets'] if a['content_type'] == win_exe), None)
|
||||||
|
download_url = asset['browser_download_url']
|
||||||
|
download_file = asset['name']
|
||||||
|
|
||||||
|
file_path = os.path.join(tempfile.gettempdir(), download_file)
|
||||||
|
logger.info('Downloading installer to temporary directory: %s', file_path)
|
||||||
|
try:
|
||||||
with requests.get(download_url, stream=True) as r:
|
with requests.get(download_url, stream=True) as r:
|
||||||
with open(file_path, 'wb') as f:
|
with open(file_path, 'wb') as f:
|
||||||
shutil.copyfileobj(r.raw, f)
|
shutil.copyfileobj(r.raw, f)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error('Failed to download %s: %s', download_file, e)
|
||||||
|
return 2
|
||||||
|
|
||||||
logger.info('Stopping Tautulli')
|
logger.info('Stopping Tautulli processes')
|
||||||
try:
|
try:
|
||||||
killed = kill_if_exists('Tautulli.exe')
|
processes = kill_and_get_processes('Tautulli.exe')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Failed to stop Tautulli: %s', e)
|
logger.error('Failed to stop Tautulli: %s', e)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
if killed != 0:
|
logger.info('Running %s', download_file)
|
||||||
logger.error('Failed to stop Tautulli')
|
try:
|
||||||
return 1
|
subprocess.call([file_path, '/S', '/NORUN'], creationflags=CREATE_NO_WINDOW)
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception('Failed to install Tautulli: %s', e)
|
||||||
|
return -1
|
||||||
|
|
||||||
logger.info('Running %s', download_file)
|
logger.info('Tautulli updated to %s', version)
|
||||||
try:
|
|
||||||
subprocess.call(
|
|
||||||
[file_path, '/S'],
|
|
||||||
creationflags=CREATE_NO_WINDOW)
|
|
||||||
except Exception as e:
|
|
||||||
logger.exception('Failed to install Tautulli: %s', e)
|
|
||||||
return -1
|
|
||||||
|
|
||||||
logger.info('Tautulli updated to %s', version)
|
logger.info('Restarting Tautulli processes')
|
||||||
|
for process in processes:
|
||||||
|
logger.info('Starting process: %s', process)
|
||||||
|
subprocess.Popen(process, creationflags=CREATE_NO_WINDOW)
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
status = update_tautulli()
|
try:
|
||||||
|
status = update_tautulli()
|
||||||
|
except Exception as exc:
|
||||||
|
status = exc
|
||||||
logger.debug('Update function returned %s', status)
|
logger.debug('Update function returned %s', status)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue