2019-08-21 14:54:05 +02:00
# -*- 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
2019-08-20 10:14:54 +02:00
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
2019-08-26 16:50:51 +02:00
import datetime
2019-07-09 16:13:16 +02:00
2019-08-20 10:14:54 +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
2019-08-12 17:07:37 +02:00
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
def updateChannel ( choice ) :
if choice == " Beta " :
with open ( globs . CNIRUrlConfig , ' w ' ) as ( configFile ) :
configFile . write ( " {} \n 0 \n 0 " . format ( globs . CNIRBetaURL ) )
else :
with open ( globs . CNIRUrlConfig , ' w ' ) as ( configFile ) :
configFile . write ( " {} \n 0 \n 0 " . format ( globs . CNIRDefaultURL ) )
2019-07-11 16:04:18 +02:00
2019-07-12 10:57:03 +02:00
def getLatestVersion ( credentials ) :
"""
Returns the latest version of the software
"""
2019-08-20 10:14:54 +02:00
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 ( " {} \n 0 \n 0 " . 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-08-20 10:14:54 +02:00
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 )
2019-08-20 10:14:54 +02:00
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 " )
2019-08-12 17:07:37 +02:00
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
2019-08-12 17:07:37 +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 " )
2019-08-12 17:07:37 +02:00
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 " )
2019-08-12 17:07:37 +02:00
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
2019-08-12 17:07:37 +02:00
# hide main window
2019-08-20 10:14:54 +02:00
pythoncom . CoInitialize ( )
2019-08-12 17:07:37 +02:00
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
2019-08-12 17:07:37 +02:00
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
2019-08-12 17:07:37 +02:00
if len ( sys . argv ) > 2 and str ( sys . argv [ 1 ] ) == " DELETE " :
2019-08-02 10:28:14 +02:00
globs . CNIRNewVersion = True
2019-08-12 17:07:37 +02:00
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 :
2019-08-12 17:07:37 +02:00
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 ( )
2019-08-12 17:07:37 +02:00
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 ) )
2019-08-12 17:07:37 +02:00
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
2019-08-26 16:50:51 +02:00
credentials = downloader . newcredentials ( )
if not credentials . valid :
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 :
critical . crashCNIR ( )
raise IOError ( str ( e ) )
else :
# 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 ( )
raise IOError ( str ( e ) )
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-26 16:50:51 +02:00
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-20 10:14:54 +02:00
critical . crashCNIR ( )
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-07-09 16:13:16 +02:00
else :
logfile . printerr ( " An error occured. No effective update ! " )
2019-08-12 17:07:37 +02:00
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
if UPDATE_IS_MADE :
launcherWindow . exit ( )
return 0
except :
2019-08-20 10:14:54 +02:00
critical . crashCNIR ( )
2019-08-07 15:30:22 +02:00
launcherWindow . exit ( )
2019-08-11 21:16:20 +02:00
sys . exit ( 2 )
return 2
try :
try :
# INSTALLING TESSERACT OCR
success = tessInstall ( globs . CNIRFolder , credentials )
except Exception as e :
2019-08-20 10:14:54 +02:00
critical . crashCNIR ( )
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 ! " )
2019-08-12 17:07:37 +02:00
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 ! " )
2019-08-12 17:07:37 +02:00
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-20 10:14:54 +02:00
critical . crashCNIR ( )
2019-08-07 15:30:22 +02:00
launcherWindow . exit ( )
2019-08-26 13:45:33 +02:00
exitProcess ( 2 )
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