dir creation handling

This commit is contained in:
Ondrej Samohel 2020-09-16 09:56:16 +02:00
parent 28be966c37
commit 3fe4300ca3
No known key found for this signature in database
GPG key ID: 8A29C663C672C2B7
3 changed files with 102 additions and 24 deletions

View file

@ -10,7 +10,7 @@ import os
import logging as log
import shutil
import tempfile
from typing import Union
from typing import Union, Callable
from zipfile import ZipFile
from appdirs import user_data_dir
@ -46,23 +46,40 @@ class BootstrapRepos():
"""Get version of local Pype."""
return __version__
def install_live_repos(self) -> Union[str, None]:
def install_live_repos(self, progress_callback=None) -> Union[str, None]:
"""Copy zip created from local repositories to user data dir.
Args:
progress_callback (callable): Optional callback method to report
progress.
Returns:
str: path of installed repository file.
"""
# dummy progress reporter
def empty_progress(x: int):
return x
if not progress_callback:
progress_callback = empty_progress
# create zip from repositories
local_version = self.get_local_version()
repo_dir = self.live_repo_dir
# create destination directory
try:
os.makedirs(self.data_dir)
except OSError:
self._log.error("directory already exists")
with tempfile.TemporaryDirectory() as temp_dir:
temp_zip = os.path.join(
str(temp_dir),
temp_dir,
f"pype-repositories-v{local_version}.zip"
)
self._log.info(f"creating zip: {temp_zip}")
# shutil.make_archive(temp_zip, "zip", repo_dir)
self._create_pype_zip(temp_zip, repo_dir)
self._create_pype_zip(
temp_zip, repo_dir, progress_callback=progress_callback)
if not os.path.exists(temp_zip):
self._log.error("make archive failed.")
return None
@ -70,7 +87,8 @@ class BootstrapRepos():
return os.path.join(self.data_dir, os.path.basename(temp_zip))
def _create_pype_zip(
self, zip_path: str, dir: str, include_pype=True) -> None:
self, zip_path: str, dir: str,
progress_callback: Callable, include_pype: bool = True) -> None:
"""Pack repositories and Pype into zip.
We are using `zipfile` instead :meth:`shutil.make_archive()` to later
@ -83,10 +101,20 @@ class BootstrapRepos():
Args:
zip_path (str): path to zip file.
dir: repo directories to inlcude.
progress_callback (Callable): callback to report progress back to
UI progress bar.
include_pype (bool): add Pype module itelf.
"""
repo_files = sum(len(files) for _, _, files in os.walk(dir))
if include_pype:
pype_files = sum(len(files) for _, _, files in os.walk('pype'))
repo_inc = 48.0 / float(repo_files)
pype_inc = 48.0 / float(pype_files)
else:
repo_inc = 98.0 / float(repo_files)
progress = 0
with ZipFile(zip_path, "w") as zip:
for root, dirs, files in os.walk(dir):
for root, _, files in os.walk(dir):
for file in files:
zip.write(
os.path.relpath(os.path.join(root, file),
@ -94,9 +122,11 @@ class BootstrapRepos():
os.path.relpath(os.path.join(root, file),
os.path.join(dir))
)
progress += repo_inc
progress_callback(int(progress))
# add pype itself
if include_pype:
for root, dirs, files in os.walk("pype"):
for root, _, files in os.walk("pype"):
for file in files:
zip.write(
os.path.relpath(os.path.join(root, file),
@ -106,7 +136,10 @@ class BootstrapRepos():
os.path.relpath(os.path.join(root, file),
os.path.join('pype', '..')))
)
progress += pype_inc
progress_callback(int(progress))
zip.testzip()
progress_callback(100)
def add_paths_from_archive(self, archive: str) -> None:
"""Add first-level directories as paths to sys.path.

View file

@ -11,6 +11,7 @@ class InstallDialog(QtWidgets.QDialog):
_size_w = 400
_size_h = 300
_path = None
_controls_disabled = False
def __init__(self, parent=None):
super(InstallDialog, self).__init__(parent)
@ -30,6 +31,18 @@ class InstallDialog(QtWidgets.QDialog):
self.setMaximumSize(
QtCore.QSize(self._size_w + 100, self._size_h + 100))
# style for normal console text
self.default_console_style = QtGui.QTextCharFormat()
self.default_console_style.setFontPointSize(0.1)
self.default_console_style.setForeground(
QtGui.QColor.fromRgb(72, 200, 150))
# style for error console text
self.error_console_style = QtGui.QTextCharFormat()
self.error_console_style.setFontPointSize(0.1)
self.error_console_style.setForeground(
QtGui.QColor.fromRgb(184, 54, 19))
self._init_ui()
def _init_ui(self):
@ -96,7 +109,6 @@ class InstallDialog(QtWidgets.QDialog):
# Bottom button bar
# --------------------------------------------------------------------
bottom_widget = QtWidgets.QWidget()
bottom_layout = QtWidgets.QHBoxLayout()
pype_logo_label = QtWidgets.QLabel("pype logo")
@ -138,18 +150,22 @@ class InstallDialog(QtWidgets.QDialog):
# Status label
# --------------------------------------------------------------------
self._status_label = QtWidgets.QLabel()
self._status_label = QtWidgets.QLabel("Console:")
self._status_label.setContentsMargins(0, 10, 0, 10)
self._status_label.setStyleSheet("color: rgb(61, 115, 97);")
# Console
# --------------------------------------------------------------------
self._status_box = QtWidgets.QPlainTextEdit()
self._status_box.setReadOnly(True)
self._status_box.setCurrentCharFormat(self.default_console_style)
self._status_box.setStyleSheet(
"""QPlainTextEdit {
background-color: rgb(32, 32, 32);
color: rgb(72, 200, 150);
font-family: Courier;
font-size: .3em;}
font-size: 3pt;
}
QScrollBar:vertical {
border: 1px solid rgb(61, 115, 97);
background: #000;
@ -181,12 +197,33 @@ class InstallDialog(QtWidgets.QDialog):
"""
)
# Progress bar
# --------------------------------------------------------------------
self._progress_bar = QtWidgets.QProgressBar()
self._progress_bar.setValue(0)
self._progress_bar.setAlignment(QtCore.Qt.AlignCenter)
self._progress_bar.setTextVisible(False)
# setting font and the size
self._progress_bar.setFont(QtGui.QFont('Arial', 7))
self._progress_bar.setStyleSheet(
"""QProgressBar:horizontal {
height: 5px;
border: 1px solid rgb(31, 62, 50);
color: rgb(72, 200, 150);
}
QProgressBar::chunk:horizontal {
background-color: rgb(72, 200, 150);
}
"""
)
# add all to main
main.addWidget(self.main_label)
main.addWidget(self.pype_path_label)
main.addLayout(input_layout)
main.addStretch(1)
main.addWidget(self._status_label)
main.addWidget(self._status_box)
main.addWidget(self._progress_bar)
main.addWidget(bottom_widget)
self.setLayout(main)
@ -204,12 +241,13 @@ class InstallDialog(QtWidgets.QDialog):
self._disable_buttons()
self._install_thread = InstallThread(self)
self._install_thread.message.connect(self._update_console)
self._install_thread.progress.connect(self._update_progress)
self._install_thread.finished.connect(self._enable_buttons)
self._install_thread.set_path(self._path)
self._install_thread.start()
def _update_console(self, msg):
self._status_box.appendPlainText(msg)
def _update_progress(self, progress: int):
self._progress_bar.setValue(progress)
def _on_exit_clicked(self):
self.close()
@ -218,7 +256,7 @@ class InstallDialog(QtWidgets.QDialog):
self._path = path
self._status_label.setText(f"selected <b>{path}</b>")
def _update_status(self, msg: str, error: bool = False) -> None:
def _update_console(self, msg: str, error: bool = False) -> None:
"""Display message.
Args:
@ -226,22 +264,22 @@ class InstallDialog(QtWidgets.QDialog):
error (bool): if True, print it red.
"""
if not error:
self._status_label.setStyleSheet("color: rgb(72, 200, 150);")
self._status_box.setCurrentCharFormat(self.default_console_style)
else:
self._status_label.setStyleSheet("color: rgb(189, 54, 32);")
self._status_label.setText(msg)
self._status_box.setCurrentCharFormat(self.error_console_style)
self._status_box.appendPlainText(msg)
def _disable_buttons(self):
self._btn_select.setEnabled(False)
self._exit_button.setEnabled(False)
self._ok_button.setEnabled(False)
self._controls_disabled(True)
self._controls_disabled = True
def _enable_buttons(self):
self._btn_select.setEnabled(True)
self._exit_button.setEnabled(True)
self._ok_button.setEnabled(True)
self._controls_disabled(False)
self._controls_disabled = False
def closeEvent(self, event):
if self._controls_disabled:

View file

@ -8,14 +8,15 @@ from .bootstrap_repos import BootstrapRepos
class InstallThread(QThread):
message = Signal(str)
progress = Signal(int)
message = Signal((str, bool))
_path = None
def __init__(self, parent=None):
QThread.__init__(self, parent)
def run(self):
self.message.emit("Installing Pype ...")
self.message.emit("Installing Pype ...", False)
bs = BootstrapRepos()
local_version = bs.get_local_version()
@ -28,11 +29,17 @@ class InstallThread(QThread):
# version to it.
if not self._path:
self.message.emit(
f"We will use local Pype version {local_version}")
repo_file = bs.install_live_repos()
f"We will use local Pype version {local_version}", False)
repo_file = bs.install_live_repos(
progress_callback=self.set_progress)
if not repo_file:
self.message.emit(f"!!! install failed - {repo_file}")
self.message.emit(f"installed as {repo_file}")
self.message.emit(
f"!!! install failed - {repo_file}", True)
return
self.message.emit(f"installed as {repo_file}", False)
def set_path(self, path: str) -> None:
self._path = path
def set_progress(self, progress: int):
self.progress.emit(progress)