CNIRevelator/src/updater.py

490 lines
17 KiB
Python
Raw Permalink Normal View History

# -*- coding: utf8 -*-
2019-07-09 16:13:16 +02:00
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher updating system *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
from win32com.client import Dispatch
from tkinter.messagebox import *
from tkinter import *
import pythoncom
2019-07-09 16:13:16 +02:00
import sys
import time
2019-07-09 16:43:47 +02:00
import os
2019-07-10 00:20:39 +02:00
import shutil
import zipfile
2019-07-10 01:12:58 +02:00
import hashlib
2019-07-10 16:50:40 +02:00
import subprocess
2019-07-10 23:05:23 +02:00
import psutil
import datetime
2019-07-09 16:13:16 +02:00
import critical # critical.py
2019-08-23 16:46:25 +02:00
import github # github.py
2019-08-07 16:39:37 +02:00
import ihm # ihm.py
2019-07-09 16:13:16 +02:00
import logger # logger.py
import globs # globs.py
import downloader # downloader.py
import lang # lang.py
2019-07-09 16:13:16 +02:00
2019-07-10 11:47:54 +02:00
UPDATE_IS_MADE = False
2019-07-10 16:50:40 +02:00
UPATH = ' '
2019-07-10 11:47:54 +02:00
2019-08-07 15:30:22 +02:00
launcherWindow = ihm.launcherWindowCur
2019-07-09 16:13:16 +02:00
def createShortcut(path, target='', wDir='', icon=''):
2019-07-12 10:57:03 +02:00
"""
Creates a shortcut for a program or an internet link
"""
2019-07-09 16:13:16 +02:00
ext = path[-3:]
if ext == 'url':
shortcut = file(path, 'w')
shortcut.write('[InternetShortcut]\n')
shortcut.write('URL=%s' % target)
shortcut.close()
else:
shell = Dispatch('WScript.Shell')
2019-08-10 22:00:32 +02:00
shortcut = shell.CreateShortCut(shell.SpecialFolders("Desktop") + r"\{}".format(path))
2019-07-09 16:13:16 +02:00
shortcut.Targetpath = target
shortcut.WorkingDirectory = wDir
if icon == '':
pass
else:
shortcut.IconLocation = icon
shortcut.save()
2019-07-10 16:50:40 +02:00
def spawnProcess(args, cd):
2019-07-12 10:57:03 +02:00
"""
Creates a new independant process. Used to launch a new version after update
"""
2019-07-10 16:50:40 +02:00
subprocess.Popen(args, close_fds=True, cwd=cd, creationflags=subprocess.DETACHED_PROCESS)
2019-07-11 16:04:18 +02:00
def exitProcess(arg):
2019-07-12 10:57:03 +02:00
"""
Forcefully quits a process. Used to help deletion of an old version or to quit properly
"""
2019-07-11 16:04:18 +02:00
# Quit totally without remain in memory
for process in psutil.process_iter():
if process.pid == os.getpid():
process.terminate()
sys.exit(arg)
2019-08-19 17:56:23 +02:00
2019-08-29 12:54:43 +02:00
def setUpdateChannel(choice):
"""
Sets the new update channel and forces new update at next launch
"""
2019-08-19 17:56:23 +02:00
if choice == "Beta":
with open(globs.CNIRUrlConfig, 'w') as (configFile):
configFile.write("{}\n0\n0".format(globs.CNIRBetaURL))
2019-08-29 12:54:43 +02:00
# Force new update
try:
os.remove(globs.CNIRLastUpdate)
except:
pass
elif choice == "Stable":
2019-08-19 17:56:23 +02:00
with open(globs.CNIRUrlConfig, 'w') as (configFile):
configFile.write("{}\n0\n0".format(globs.CNIRDefaultURL))
2019-08-29 12:54:43 +02:00
# Force new update
try:
os.remove(globs.CNIRLastUpdate)
except:
pass
def getUpdateChannel():
"""
Returns the current update channel
"""
with open(globs.CNIRUrlConfig, 'r') as (configFile):
url = configFile.read()
if not "master" in url:
return "Beta"
else:
return "Stable"
2019-07-12 10:57:03 +02:00
def getLatestVersion(credentials):
"""
Returns the latest version of the software
"""
finalver, finalurl, finalchecksum = [None]*3
2019-07-09 16:13:16 +02:00
# Global Handlers
logfile = logger.logCur
2019-08-07 15:30:22 +02:00
2019-07-09 16:13:16 +02:00
# First retrieving the urls !
while True:
try:
# Open the config file
logfile.printdbg('Reading urlconf.ig')
with open(globs.CNIRUrlConfig, 'r') as (configFile):
try:
# Reading it
reading = configFile.read()
# Parsing it
urlparsed = reading.split("\n")
break
except Exception as e:
raise IOError(str(e))
except FileNotFoundError:
logfile.printdbg('Recreate urlconf.ig')
# Recreating the url file
2019-07-09 16:43:47 +02:00
try:
os.mkdir(globs.CNIRFolder + '\\config')
except:
pass
2019-07-09 16:13:16 +02:00
with open(globs.CNIRUrlConfig, 'w') as (configFile):
2019-08-19 17:56:23 +02:00
configFile.write("{}\n0\n0".format(globs.CNIRDefaultURL))
2019-07-09 16:13:16 +02:00
# Getting the list of versions of the software
logfile.printdbg('Retrieving the software versions')
2019-07-09 16:43:47 +02:00
try:
os.mkdir(globs.CNIRFolder + '\\downloads')
except:
pass
2019-08-05 15:52:02 +02:00
getTheVersions = downloader.newdownload(credentials, urlparsed[0], globs.CNIRVerStock, "the version repository").download()
2019-07-09 16:13:16 +02:00
logfile.printdbg('Parsing the software versions')
2019-07-09 16:52:23 +02:00
with open(globs.CNIRVerStock) as versionsFile:
2019-07-09 16:13:16 +02:00
versionsTab = versionsFile.read().split("\n")[1].split("||")
logfile.printdbg('Versions retrieved : {}'.format(versionsTab))
# Choose the newer
finalver = globs.version.copy()
for entry in versionsTab:
2019-07-10 00:29:05 +02:00
if not entry:
2019-08-05 15:52:02 +02:00
continue
2019-07-09 16:13:16 +02:00
verstr, url, checksum = entry.split("|")
# Calculating sum considering we can have 99 sub versions
ver = verstr.split(".")
ver = [int(i) for i in ver]
finalsum = finalver[2] + finalver[1]*100 + finalver[0]*100*100
sum = ver[2] + ver[1]*100 + ver[0]*100*100
# Make a statement
2019-07-12 10:57:03 +02:00
if sum >= finalsum:
2019-07-09 16:13:16 +02:00
finalver = ver.copy()
finalurl = url
2019-07-10 01:23:48 +02:00
finalchecksum = checksum
2019-08-05 15:52:02 +02:00
else:
2019-08-06 09:48:31 +02:00
finalurl = url
2019-08-05 15:52:02 +02:00
finalchecksum = None
2019-07-12 10:57:03 +02:00
return (finalver, finalurl, finalchecksum)
2019-08-02 11:08:53 +02:00
2019-07-12 10:57:03 +02:00
def tessInstall(PATH, credentials):
# Global Handlers
logfile = logger.logCur
2019-08-07 15:30:22 +02:00
2019-07-12 10:57:03 +02:00
# Verifying that Tesseract is installed
2019-08-20 18:38:22 +02:00
if not os.path.exists(PATH + '\\Tesseract-OCR5\\'):
2019-07-12 10:57:03 +02:00
finalver, finalurl, finalchecksum = getLatestVersion(credentials)
if finalurl == None:
logfile.printerr('Unable to get the Tesseract url')
return False
2019-08-20 18:38:22 +02:00
tesseracturl = finalurl.replace("CNIRevelator.zip", "tesseract_5.zip")
2019-07-12 10:57:03 +02:00
2019-08-20 18:38:22 +02:00
# WE ASSUME THAT THE MAIN FILE IS CNIRevelator.zip AND THAT THE TESSERACT PACKAGE IS tesseract_5.zip
2019-07-12 10:57:03 +02:00
logfile.printdbg('Preparing download of Tesseract OCR 4...')
2019-08-20 18:38:22 +02:00
getTesseract = downloader.newdownload(credentials, tesseracturl, PATH + '\\downloads\\TsrtPackage.zip', "Tesseract 5 OCR Module").download()
2019-07-12 10:57:03 +02:00
try:
2019-08-11 23:57:30 +02:00
# CHECKSUM
BUF_SIZE = 65536 # lets read stuff in 64kb chunks!
sha1 = hashlib.sha1()
with open(globs.CNIRFolder + '\\downloads\\TsrtPackage.zip', 'rb') as f:
while True:
data = f.read(BUF_SIZE)
if not data:
break
sha1.update(data)
check = sha1.hexdigest()
logfile.printdbg("SHA1: {0}".format(check))
if not check == globs.CNIRTesserHash:
logfile.printerr("Checksum error")
return False
2019-08-11 21:16:20 +02:00
# Unzip Tesseract
logfile.printdbg("Unzipping the package")
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Installing the updates"])
2019-08-11 21:16:20 +02:00
zip_ref = zipfile.ZipFile(PATH + '\\downloads\\TsrtPackage.zip', 'r')
zip_ref.extractall(PATH)
zip_ref.close()
# Cleanup
try:
os.remove(UPATH + '\\downloads\\TsrtPackage.zip')
except:
pass
return True
2019-07-12 10:57:03 +02:00
except:
2019-08-11 21:16:20 +02:00
return False
else:
return True
2019-07-12 10:57:03 +02:00
## Main Batch Function
def batch(credentials):
# Global Handlers
logfile = logger.logCur
2019-08-07 15:30:22 +02:00
2019-07-09 16:13:16 +02:00
2019-07-12 10:57:03 +02:00
# Get the latest version of CNIRevelator
finalver, finalurl, finalchecksum = getLatestVersion(credentials)
2019-07-09 16:13:16 +02:00
if finalver == globs.version:
logfile.printdbg('The software is already the newer version')
return True
logfile.printdbg('Preparing download for the new version')
2019-08-05 15:52:02 +02:00
getTheUpdate = downloader.newdownload(credentials, finalurl, globs.CNIRFolder + '\\downloads\\CNIPackage.zip', "CNIRevelator {}.{}.{}".format(finalver[0], finalver[1], finalver[2])).download()
2019-07-10 01:12:58 +02:00
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Verifying download..."])
2019-07-10 10:12:54 +02:00
2019-07-11 10:30:12 +02:00
# CHECKSUM
2019-07-10 01:12:58 +02:00
BUF_SIZE = 65536 # lets read stuff in 64kb chunks!
sha1 = hashlib.sha1()
2019-08-05 15:52:02 +02:00
with open(globs.CNIRFolder + '\\downloads\\CNIPackage.zip', 'rb') as f:
2019-07-10 01:12:58 +02:00
while True:
data = f.read(BUF_SIZE)
if not data:
break
sha1.update(data)
2019-07-10 01:23:48 +02:00
check = sha1.hexdigest()
logfile.printdbg("SHA1: {0}".format(check))
2019-07-10 01:12:58 +02:00
2019-07-10 01:23:48 +02:00
if not check == finalchecksum:
logfile.printerr("Checksum error")
return False
2019-07-09 16:13:16 +02:00
2019-07-10 16:50:40 +02:00
# And now prepare install
global UPATH
2019-07-10 10:48:14 +02:00
UPATH = globs.CNIRFolder + '\\..\\CNIRevelator' + "{}.{}.{}".format(finalver[0], finalver[1], finalver[2])
2019-07-10 10:12:54 +02:00
logfile.printdbg("Make place")
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Preparing installation..."])
2019-07-10 16:50:40 +02:00
# Cleanup
2019-07-10 10:12:54 +02:00
try:
2019-07-10 10:48:14 +02:00
shutil.rmtree(UPATH + 'temp')
2019-07-10 16:50:40 +02:00
except Exception as e:
logfile.printdbg('Unable to cleanup : ' +str(e))
try:
2019-07-10 10:48:14 +02:00
shutil.rmtree(UPATH)
2019-07-10 16:50:40 +02:00
except Exception as e:
logfile.printdbg('Unable to cleanup : ' +str(e))
# Unzip
2019-07-10 01:12:58 +02:00
logfile.printdbg("Unzipping the package")
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Installing the updates"])
2019-08-05 15:52:02 +02:00
zip_ref = zipfile.ZipFile(globs.CNIRFolder + '\\downloads\\CNIPackage.zip', 'r')
2019-07-10 10:48:14 +02:00
zip_ref.extractall(UPATH + "temp")
2019-07-10 00:20:39 +02:00
zip_ref.close()
2019-07-10 10:48:14 +02:00
# Move to the right place
shutil.copytree(UPATH + 'temp\\CNIRevelator', UPATH)
shutil.rmtree(UPATH + 'temp')
2019-07-11 11:16:41 +02:00
logfile.printdbg('Extracted :' + UPATH + '\\CNIRevelator.exe')
2019-08-10 22:00:32 +02:00
# Make a shortcut
# hide main window
pythoncom.CoInitialize()
root = Tk()
root.withdraw()
res = askquestion(lang.all[globs.CNIRlang]["Shortcut creation"], lang.all[globs.CNIRlang]["Would you like to create/update the shortcut for CNIRevelator on your desktop ?"])
if res == "yes":
createShortcut("CNIRevelator.lnk", UPATH + '\\CNIRevelator.exe', UPATH)
root.destroy()
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Success !"])
2019-07-10 01:23:48 +02:00
2019-07-10 11:47:54 +02:00
# Cleanup
try:
2019-08-05 15:52:02 +02:00
os.remove(globs.CNIRFolder + '\\downloads\\CNIPackage.zip')
2019-07-10 11:47:54 +02:00
except:
pass
2019-07-10 16:50:40 +02:00
# Time to quit
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Launching the new version..."])
2019-07-10 16:50:40 +02:00
global UPDATE_IS_MADE
2019-07-10 11:47:54 +02:00
UPDATE_IS_MADE = True
return True
2019-07-09 16:13:16 +02:00
## Main Function
def umain():
2019-07-10 00:20:39 +02:00
2019-07-10 16:50:40 +02:00
# Global Handlers
logfile = logger.logCur
2019-07-12 10:57:03 +02:00
2019-07-10 23:05:23 +02:00
# Cleaner for the old version if detected
if len(sys.argv) > 2 and str(sys.argv[1]) == "DELETE":
2019-08-02 10:28:14 +02:00
globs.CNIRNewVersion = True
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Deleting old version"])
2019-08-26 13:45:33 +02:00
logfile.printdbg("Old install detected : {}".format(sys.argv[2]))
2019-08-02 10:28:14 +02:00
while os.path.exists(str(sys.argv[2])):
try:
shutil.rmtree(str(sys.argv[2]))
2019-08-02 10:28:14 +02:00
except Exception as e:
logfile.printerr(str(e))
logfile.printdbg('Trying stop the process !')
launcherWindow.printmsg('Fail :{}'.format(e))
try:
for process in psutil.process_iter():
if process.name() == 'CNIRevelator.exe':
logfile.printdbg('Process found. Command line: {}'.format(process.cmdline()))
if process.pid == os.getpid():
logfile.printdbg("Don't touch us ! {} = {}".format(process.pid, os.getpid()))
else:
logfile.printdbg('Terminating process !')
process.terminate()
shutil.rmtree(str(sys.argv[2]))
2019-08-02 10:28:14 +02:00
break
except Exception as e:
logfile.printerr(str(e))
launcherWindow.printmsg('Fail :{}'.format(e))
launcherWindow.printmsg(lang.all[globs.CNIRlang]['Starting...'])
# check we want open a file
elif len(sys.argv) > 1 and str(sys.argv[1]) != "DELETE":
globs.CNIROpenFile = True
2019-08-26 13:45:33 +02:00
logfile.printdbg("Command line received : {}".format(sys.argv))
2019-07-10 00:20:39 +02:00
credentials = downloader.newcredentials()
if not credentials.valid:
if credentials.login == "nointernet":
logfile.printerr("No Internet Error. No effective update !")
launcherWindow.printmsg(lang.all[globs.CNIRlang]["No Internet Error. No effective update !"])
else:
logfile.printerr("Credentials Error. No effective update !")
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Credentials Error. No effective update !"])
time.sleep(2)
launcherWindow.exit()
return 0
github.credentials = credentials
# Check if update is needed
currentDate = datetime.datetime.now()
if os.path.isfile(globs.CNIRLastUpdate):
with open(globs.CNIRLastUpdate, 'r') as (configFile):
try:
# Reading it
lastUpdate = datetime.datetime.strptime(configFile.read(),"%d/%m/%Y")
except Exception as e:
2019-08-29 11:04:50 +02:00
critical.crashCNIR(False)
time.sleep(3)
launcherWindow.exit()
return 1
else:
2019-08-29 11:04:50 +02:00
lastUpdate = datetime.datetime(1970,1,1)
2019-08-27 09:26:16 +02:00
if not globs.CNIRNewVersion and os.path.exists(globs.CNIRFolder + '\\Tesseract-OCR5\\') and (currentDate - lastUpdate).days < 7:
2019-08-29 11:04:50 +02:00
logfile.printdbg("No need to update, {} days remaining".format(7 - (currentDate - lastUpdate).days))
launcherWindow.exit()
return 0
# Update batch
2019-07-09 16:13:16 +02:00
try:
try:
# EXECUTING THE UPDATE BATCH
2019-07-12 10:57:03 +02:00
success = batch(credentials)
2019-07-09 16:13:16 +02:00
except Exception as e:
2019-08-29 11:04:50 +02:00
critical.crashCNIR(False)
2019-07-10 16:50:40 +02:00
launcherWindow.printmsg('ERROR : ' + str(e))
2019-07-09 16:13:16 +02:00
time.sleep(3)
2019-08-07 15:30:22 +02:00
launcherWindow.exit()
2019-07-09 16:13:16 +02:00
return 1
if success:
logfile.printdbg("Software is up-to-date !")
2019-07-10 16:50:40 +02:00
launcherWindow.printmsg('Software is up-to-date !')
2019-08-29 11:04:50 +02:00
# Recreating the url file
lastUpdate = currentDate
try:
os.mkdir(globs.CNIRFolder + '\\config')
except:
pass
with open(globs.CNIRLastUpdate, 'w') as (configFile):
try:
# Writing it
configFile.write("{}/{}/{}".format(currentDate.day, currentDate.month, currentDate.year))
except Exception as e:
critical.crashCNIR(False)
time.sleep(3)
launcherWindow.exit()
return
if UPDATE_IS_MADE:
launcherWindow.exit()
return 0
2019-07-09 16:13:16 +02:00
else:
logfile.printerr("An error occured. No effective update !")
launcherWindow.printmsg(lang.all[globs.CNIRlang]['An error occured. No effective update !'])
2019-08-11 21:16:20 +02:00
time.sleep(2)
launcherWindow.exit()
return 0
2019-08-29 11:04:50 +02:00
2019-08-11 21:16:20 +02:00
except:
2019-08-29 11:04:50 +02:00
critical.crashCNIR(False)
2019-08-07 15:30:22 +02:00
launcherWindow.exit()
2019-08-11 21:16:20 +02:00
return 2
try:
try:
# INSTALLING TESSERACT OCR
success = tessInstall(globs.CNIRFolder, credentials)
except Exception as e:
2019-08-29 11:04:50 +02:00
critical.crashCNIR(False)
2019-08-11 21:16:20 +02:00
launcherWindow.printmsg('ERROR : ' + str(e))
time.sleep(3)
launcherWindow.exit()
return 1
if success:
logfile.printdbg("Software is up-to-date !")
launcherWindow.printmsg(lang.all[globs.CNIRlang]['Software is up-to-date !'])
2019-08-11 21:16:20 +02:00
else:
logfile.printerr("An error occured. No effective update !")
launcherWindow.printmsg(lang.all[globs.CNIRlang]['An error occured. No effective update !'])
2019-08-11 21:16:20 +02:00
time.sleep(2)
launcherWindow.exit()
return 0
2019-07-09 16:13:16 +02:00
except:
2019-08-29 11:04:50 +02:00
critical.crashCNIR(False)
2019-08-07 15:30:22 +02:00
launcherWindow.exit()
2019-07-09 16:13:16 +02:00
return 2
2019-08-11 21:16:20 +02:00
time.sleep(2)
launcherWindow.exit()
return 0