logging, threading and file watchers, finally it's going well.
parent
841fd1cbfa
commit
fd0e5ddc3c
|
@ -1,6 +1,7 @@
|
||||||
|
from multiprocessing.util import get_logger
|
||||||
|
|
||||||
import jinja2 as j2
|
import jinja2 as j2
|
||||||
import yaml
|
import yaml
|
||||||
import subprocess
|
|
||||||
import shutil
|
import shutil
|
||||||
import requests
|
import requests
|
||||||
import os
|
import os
|
||||||
|
@ -15,8 +16,7 @@ from PIL import Image
|
||||||
from mutagen.oggvorbis import OggVorbis
|
from mutagen.oggvorbis import OggVorbis
|
||||||
from distutils.dir_util import copy_tree
|
from distutils.dir_util import copy_tree
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from widgets import create_logger
|
from subprocess import PIPE, STDOUT, CalledProcessError, CompletedProcess, Popen
|
||||||
|
|
||||||
|
|
||||||
def rmfulldir(dirpath):
|
def rmfulldir(dirpath):
|
||||||
try:
|
try:
|
||||||
|
@ -43,9 +43,23 @@ def get_ffmpeg_version():
|
||||||
return ffmpeg_version
|
return ffmpeg_version
|
||||||
|
|
||||||
|
|
||||||
|
def stream_command(args, *, stdout_handler=logging.info, check=True, text=True,
|
||||||
|
stdout=PIPE, stderr=STDOUT, **kwargs):
|
||||||
|
"""Mimic subprocess.run, while processing the command output in real time."""
|
||||||
|
with Popen(args, text=text, stdout=stdout, stderr=stderr, **kwargs) as process:
|
||||||
|
for line in process.stdout:
|
||||||
|
stdout_handler(line[:-1])
|
||||||
|
return_code = process.poll()
|
||||||
|
if check and return_code:
|
||||||
|
raise CalledProcessError(return_code, process.args)
|
||||||
|
return CompletedProcess(process.args, return_code)
|
||||||
|
|
||||||
|
|
||||||
class Deployer:
|
class Deployer:
|
||||||
def __init__(self, logging_handler: logging.Handler = None):
|
def __init__(self, logging_handler: logging.Handler = None):
|
||||||
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
|
logging.basicConfig(stream=sys.stdout, level=logging.INFO,
|
||||||
|
format='[%(asctime)s| %(levelname)s| %(processName)s] %(message)s')
|
||||||
|
|
||||||
self.logger = logging.getLogger()
|
self.logger = logging.getLogger()
|
||||||
|
|
||||||
if logging_handler is not None:
|
if logging_handler is not None:
|
||||||
|
@ -57,8 +71,6 @@ class Deployer:
|
||||||
self.source_dir = "./source"
|
self.source_dir = "./source"
|
||||||
self.install_dir = self.find_install_dir()
|
self.install_dir = self.find_install_dir()
|
||||||
|
|
||||||
def write_something(self):
|
|
||||||
self.logger.info("lalala")
|
|
||||||
|
|
||||||
def find_install_dir(self):
|
def find_install_dir(self):
|
||||||
self.logger.info("Trying to find Barotraumma install folder")
|
self.logger.info("Trying to find Barotraumma install folder")
|
||||||
|
@ -94,15 +106,16 @@ class Deployer:
|
||||||
self.download_and_extract(url_git_source, out_git_archive, subdir="/git")
|
self.download_and_extract(url_git_source, out_git_archive, subdir="/git")
|
||||||
|
|
||||||
def download_and_extract(self, url_source, out_archive, subdir=""):
|
def download_and_extract(self, url_source, out_archive, subdir=""):
|
||||||
self.logger.info(f"Downloading {url_source}, this may take a while.")
|
self.logger.info(f"Downloading {url_source}. This may take a while.")
|
||||||
|
|
||||||
download_via_requests(url_source, out_archive)
|
download_via_requests(url_source, out_archive)
|
||||||
time.sleep(0.7)
|
time.sleep(0.7)
|
||||||
self.logger.info("Download complete.")
|
self.logger.info("Download complete.")
|
||||||
|
|
||||||
self.logger.info(f"Extracting {out_archive}")
|
self.logger.info(f"Extracting {out_archive} with 7z")
|
||||||
extract = [f"{self.utils_dir}/7z/7za.exe", "x", out_archive, "-o" f"{self.utils_dir}{subdir}"]
|
extract = [f"{self.utils_dir}/7z/7za.exe", "x", out_archive, "-o" f"{self.utils_dir}{subdir}"]
|
||||||
subprocess.call(extract)
|
|
||||||
|
stream_command(extract, stdout_handler=self.logger.info)
|
||||||
|
|
||||||
time.sleep(0.7)
|
time.sleep(0.7)
|
||||||
self.logger.info("Removing " + out_archive)
|
self.logger.info("Removing " + out_archive)
|
||||||
|
@ -111,7 +124,7 @@ class Deployer:
|
||||||
def update(self):
|
def update(self):
|
||||||
self.logger.info(f"checking for updates via git pull.")
|
self.logger.info(f"checking for updates via git pull.")
|
||||||
pull = [f"{self.utils_dir}/git/bin/git.exe", "pull"]
|
pull = [f"{self.utils_dir}/git/bin/git.exe", "pull"]
|
||||||
subprocess.call(pull)
|
stream_command(pull, stdout_handler=self.logger.info)
|
||||||
|
|
||||||
def fetch_and_cut_song(self, tape, ffmpeg_version):
|
def fetch_and_cut_song(self, tape, ffmpeg_version):
|
||||||
python_executable = f"{self.utils_dir}/python-3.9.7-embed-amd64/python.exe"
|
python_executable = f"{self.utils_dir}/python-3.9.7-embed-amd64/python.exe"
|
||||||
|
@ -126,7 +139,7 @@ class Deployer:
|
||||||
# this is done in a separate python script because subprocess.call makes sure that the
|
# this is done in a separate python script because subprocess.call makes sure that the
|
||||||
# download process is finished before trying to cut the song
|
# download process is finished before trying to cut the song
|
||||||
|
|
||||||
subprocess.call(fetch)
|
stream_command(fetch, stdout_handler=self.logger.info)
|
||||||
|
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
@ -140,7 +153,7 @@ class Deployer:
|
||||||
cut = cut[:-7] + ["-to", f"{tape['source']['end']}"] + cut[-7:]
|
cut = cut[:-7] + ["-to", f"{tape['source']['end']}"] + cut[-7:]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
subprocess.call(cut)
|
stream_command(cut, stdout_handler=self.logger.info)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print("ffmpeg not in utils directory. Run python install_dependencies.py "
|
print("ffmpeg not in utils directory. Run python install_dependencies.py "
|
||||||
"or download the latest release version manually.")
|
"or download the latest release version manually.")
|
||||||
|
@ -152,7 +165,7 @@ class Deployer:
|
||||||
f"{self.music_dir}/{tape['identifier']}-walkman.ogg"]
|
f"{self.music_dir}/{tape['identifier']}-walkman.ogg"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
subprocess.call(walkman)
|
stream_command(walkman, stdout_handler=self.logger.info)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
self.logger.error("ffmpeg not in utils directory. Run python install_dependencies.py "
|
self.logger.error("ffmpeg not in utils directory. Run python install_dependencies.py "
|
||||||
"or download the latest release version manually.")
|
"or download the latest release version manually.")
|
||||||
|
|
|
@ -3,6 +3,7 @@ import os
|
||||||
import getpass
|
import getpass
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
from tape_editor_widgets import *
|
from tape_editor_widgets import *
|
||||||
from widgets import LabelWebLink
|
from widgets import LabelWebLink
|
||||||
|
@ -92,7 +93,7 @@ class OptionsWidget(QWidget):
|
||||||
self.options_gbox.setLayout(self.options_hbox)
|
self.options_gbox.setLayout(self.options_hbox)
|
||||||
|
|
||||||
# Update widget
|
# Update widget
|
||||||
self.update_widget = UpdateWidget(self)
|
self.update_widget = UpdateWidget(self, self.deployer)
|
||||||
# Install widget
|
# Install widget
|
||||||
self.install_widget = InstallWidget(self, self.deployer)
|
self.install_widget = InstallWidget(self, self.deployer)
|
||||||
# Console widget
|
# Console widget
|
||||||
|
@ -128,12 +129,6 @@ class OptionsWidget(QWidget):
|
||||||
"durability": self.cbox_durability.isChecked(),
|
"durability": self.cbox_durability.isChecked(),
|
||||||
"repair": self.cbox_repair.isChecked()}
|
"repair": self.cbox_repair.isChecked()}
|
||||||
|
|
||||||
def run_process(self, function, arguments):
|
|
||||||
logger = create_logger()
|
|
||||||
logger.info('Starting pooling')
|
|
||||||
p = multiprocessing.Pool()
|
|
||||||
p.apply_async(function, arguments)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: implement random local mod name
|
# TODO: implement random local mod name
|
||||||
|
|
||||||
|
@ -388,10 +383,11 @@ class ValidationWidget(QWidget):
|
||||||
|
|
||||||
|
|
||||||
class UpdateWidget(QGroupBox):
|
class UpdateWidget(QGroupBox):
|
||||||
def __init__(self, parent: QWidget):
|
def __init__(self, parent: QWidget, deployer: Deployer):
|
||||||
super().__init__("Update")
|
super().__init__("Update")
|
||||||
|
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
self.deployer = deployer
|
||||||
|
|
||||||
hr_html_string = "<hr style=\"background-color:gray;\">"
|
hr_html_string = "<hr style=\"background-color:gray;\">"
|
||||||
self.grid = QGridLayout(self)
|
self.grid = QGridLayout(self)
|
||||||
|
@ -416,16 +412,21 @@ class UpdateWidget(QGroupBox):
|
||||||
self.git_update_label = QLabel("Download update from git")
|
self.git_update_label = QLabel("Download update from git")
|
||||||
self.git_update_label_link = LabelWebLink("https://git.kompot.si/jaka/barotrauma-sunken-tapes")
|
self.git_update_label_link = LabelWebLink("https://git.kompot.si/jaka/barotrauma-sunken-tapes")
|
||||||
self.git_update_pushbutton = QPushButton("Update")
|
self.git_update_pushbutton = QPushButton("Update")
|
||||||
|
self.git_update_pushbutton.clicked.connect(self.update_action)
|
||||||
self.grid.addWidget(self.git_update_checkbox, 10, 0)
|
self.grid.addWidget(self.git_update_checkbox, 10, 0)
|
||||||
self.grid.addWidget(self.git_update_label, 10, 1)
|
self.grid.addWidget(self.git_update_label, 10, 1)
|
||||||
self.grid.addWidget(self.git_update_label_link, 11, 1)
|
self.grid.addWidget(self.git_update_label_link, 11, 1)
|
||||||
self.grid.addWidget(self.git_update_pushbutton, 10, 2)
|
self.grid.addWidget(self.git_update_pushbutton, 10, 2)
|
||||||
self.grid.addWidget(QLabel(hr_html_string), 12, 0, 1, 3)
|
self.grid.addWidget(QLabel(hr_html_string), 12, 0, 1, 3)
|
||||||
|
|
||||||
|
self.git_dir_watcher = QFileSystemWatcher()
|
||||||
|
self.git_dir_watcher.addPath(Path(self.git_dir.directory).as_posix())
|
||||||
|
self.git_dir_watcher.directoryChanged.connect(self.does_git_exist)
|
||||||
|
|
||||||
self.does_git_exist()
|
self.does_git_exist()
|
||||||
|
|
||||||
def download_git_action(self):
|
def download_git_action(self):
|
||||||
self.parent.deployer.download_git()
|
Thread(target=self.deployer.download_git).start()
|
||||||
|
|
||||||
def does_git_exist(self):
|
def does_git_exist(self):
|
||||||
executable_path = Path("git/bin/git.exe")
|
executable_path = Path("git/bin/git.exe")
|
||||||
|
@ -436,8 +437,12 @@ class UpdateWidget(QGroupBox):
|
||||||
|
|
||||||
self.git_pushbutton.setEnabled(not exists)
|
self.git_pushbutton.setEnabled(not exists)
|
||||||
self.git_checkbox.setChecked(exists)
|
self.git_checkbox.setChecked(exists)
|
||||||
|
self.git_update_pushbutton.setEnabled(exists)
|
||||||
return exists
|
return exists
|
||||||
|
|
||||||
|
def update_action(self):
|
||||||
|
Thread(target=self.deployer.update).start()
|
||||||
|
|
||||||
|
|
||||||
class ConsoleWidget(QGroupBox):
|
class ConsoleWidget(QGroupBox):
|
||||||
def __init__(self, parent: QWidget):
|
def __init__(self, parent: QWidget):
|
||||||
|
@ -445,6 +450,9 @@ class ConsoleWidget(QGroupBox):
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
||||||
self.console = QPlainTextEdit(self)
|
self.console = QPlainTextEdit(self)
|
||||||
|
self.console.setReadOnly(True)
|
||||||
|
self.console.setFont("Consolas")
|
||||||
|
self.console.setMinimumHeight(100)
|
||||||
|
|
||||||
layout = QVBoxLayout(self)
|
layout = QVBoxLayout(self)
|
||||||
layout.addWidget(self.console)
|
layout.addWidget(self.console)
|
||||||
|
@ -510,6 +518,10 @@ class InstallWidget(QGroupBox):
|
||||||
|
|
||||||
self.grid.setRowStretch(50, 20)
|
self.grid.setRowStretch(50, 20)
|
||||||
|
|
||||||
|
self.utils_dir_watcher = QFileSystemWatcher()
|
||||||
|
self.utils_dir_watcher.addPath(Path(self.ffmpeg_dir.directory).as_posix())
|
||||||
|
self.utils_dir_watcher.directoryChanged.connect(self.does_ffmpeg_exist)
|
||||||
|
|
||||||
self.does_ffmpeg_exist()
|
self.does_ffmpeg_exist()
|
||||||
|
|
||||||
def does_ffmpeg_exist(self):
|
def does_ffmpeg_exist(self):
|
||||||
|
@ -525,12 +537,7 @@ class InstallWidget(QGroupBox):
|
||||||
return exists
|
return exists
|
||||||
|
|
||||||
def download_ffmpeg_action(self):
|
def download_ffmpeg_action(self):
|
||||||
|
Thread(target=self.deployer.download_ffmpeg).start()
|
||||||
self.deployer.write_something()
|
|
||||||
|
|
||||||
#self.parent.run_process(self.deployer.download_ffmpeg, ())
|
|
||||||
#download_ffmpeg(self.ffmpeg_dir.directory)
|
|
||||||
self.does_ffmpeg_exist()
|
|
||||||
|
|
||||||
def are_songs_ready(self):
|
def are_songs_ready(self):
|
||||||
tapes = self.parent.parent.validation_widget.tapes
|
tapes = self.parent.parent.validation_widget.tapes
|
||||||
|
@ -584,9 +591,8 @@ class SignalHandler(logging.Handler):
|
||||||
super(SignalHandler, self).__init__(*args, **kwargs)
|
super(SignalHandler, self).__init__(*args, **kwargs)
|
||||||
self.emitter = QSignaler()
|
self.emitter = QSignaler()
|
||||||
|
|
||||||
def emit(self, logRecord):
|
def emit(self, log_record: logging.LogRecord):
|
||||||
msg = "{0}".format(logRecord.getMessage())
|
self.emitter.log_message.emit(f"{log_record.message}")
|
||||||
self.emitter.log_message.emit(msg)
|
|
||||||
# When the line below is enabled, logging is immediate/otherwise events
|
# When the line below is enabled, logging is immediate/otherwise events
|
||||||
# on the queue will be processed when the slot has finished.
|
# on the queue will be processed when the slot has finished.
|
||||||
# QtGui.qApp.processEvents()
|
# QtGui.qApp.processEvents()
|
||||||
|
|
|
@ -18,20 +18,6 @@ from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
def create_logger():
|
|
||||||
logger = multiprocessing.get_logger()
|
|
||||||
logger.setLevel(logging.INFO)
|
|
||||||
formatter = logging.Formatter('[%(asctime)s| %(levelname)s| %(processName)s] %(message)s')
|
|
||||||
handler = logging.StreamHandler()
|
|
||||||
handler.setFormatter(formatter)
|
|
||||||
|
|
||||||
# this bit will make sure you won't have
|
|
||||||
# duplicated messages in the output
|
|
||||||
if not len(logger.handlers):
|
|
||||||
logger.addHandler(handler)
|
|
||||||
return logger
|
|
||||||
|
|
||||||
|
|
||||||
class LabelWebLink(QLabel):
|
class LabelWebLink(QLabel):
|
||||||
def __init__(self, text):
|
def __init__(self, text):
|
||||||
text = f"<a href=\"{text}\">{text.replace('https://', '')}</a>"
|
text = f"<a href=\"{text}\">{text.replace('https://', '')}</a>"
|
||||||
|
|
Loading…
Reference in New Issue