class UnpackTab(QtWidgets.QWidget): """The unpack window, that sets up a .RPZ file in a directory. """ UNPACKERS = [ ('directory', DirectoryOptions), ('chroot', ChrootOptions), ('docker', DockerOptions), ('vagrant', VagrantOptions), ] unpacked = QtCore.Signal(str, object) def __init__(self, package='', **kwargs): super(UnpackTab, self).__init__(**kwargs) layout = QtWidgets.QGridLayout() layout.addWidget(QtWidgets.QLabel("RPZ package:"), 0, 0) self.package_widget = QtWidgets.QLineEdit(package, enabled=False) layout.addWidget(self.package_widget, 0, 1) browse_pkg = QtWidgets.QPushButton("Browse") browse_pkg.clicked.connect(self._browse_pkg) layout.addWidget(browse_pkg, 0, 2) layout.addWidget(QtWidgets.QLabel("Unpacker:"), 1, 0, QtCore.Qt.AlignTop) ulayout = QtWidgets.QVBoxLayout() self.unpackers = QtWidgets.QButtonGroup() for i, name in enumerate(n for n, c in self.UNPACKERS): radio = QtWidgets.QRadioButton(name) radio.unpacker = name self.unpackers.addButton(radio, i) ulayout.addWidget(radio) layout.addLayout(ulayout, 1, 1, 1, 2) group = QtWidgets.QGroupBox(title="Unpacker options") group_layout = QtWidgets.QVBoxLayout() self.unpacker_options = ResizableStack() self.unpackers.buttonClicked[int].connect( self.unpacker_options.setCurrentIndex) scroll = QtWidgets.QScrollArea(widgetResizable=True) scroll.setWidget(self.unpacker_options) group_layout.addWidget(scroll) group.setLayout(group_layout) layout.addWidget(group, 2, 0, 1, 3) layout.setRowStretch(2, 1) for i, (name, WidgetClass) in enumerate(self.UNPACKERS): widget = WidgetClass() self.unpacker_options.addWidget(widget) self.unpacker_options.addWidget( QtWidgets.QLabel("Select an unpacker to display options...")) self.unpacker_options.setCurrentIndex(len(self.UNPACKERS)) layout.addWidget(QtWidgets.QLabel("Destination directory:"), 3, 0) self.directory_widget = QtWidgets.QLineEdit() self.directory_widget.editingFinished.connect(self._directory_changed) layout.addWidget(self.directory_widget, 3, 1) browse_dir = QtWidgets.QPushButton("Browse") browse_dir.clicked.connect(self._browse_dir) layout.addWidget(browse_dir, 3, 2) buttons = QtWidgets.QHBoxLayout() buttons.addStretch(1) self.unpack_widget = QtWidgets.QPushButton("Unpack experiment", enabled=False) self.unpack_widget.clicked.connect(self._unpack) buttons.addWidget(self.unpack_widget) layout.addLayout(buttons, 4, 0, 1, 3) self.setLayout(layout) self._package_changed() def replaceable(self): return not self.package_widget.text() def _browse_pkg(self): picked, _ = QtWidgets.QFileDialog.getOpenFileName( self, "Pick package file", QtCore.QDir.currentPath(), "ReproZip Packages (*.rpz)") if picked: record_usage(browse_pkg=True) self.package_widget.setText(picked) self._package_changed() def _package_changed(self, new_pkg=None): package = self.package_widget.text() if package.lower().endswith('.rpz'): self.directory_widget.setText(package[:-4]) self._directory_changed() def _browse_dir(self): picked, _ = QtWidgets.QFileDialog.getSaveFileName( self, "Pick directory", QtCore.QDir.currentPath()) if picked: if os.path.exists(picked): error_msg(self, "This directory already exists", 'warning') else: self.directory_widget.setText(picked) self._directory_changed() def _directory_changed(self, new_dir=None): self.unpack_widget.setEnabled(bool(self.directory_widget.text())) def _unpack(self): directory = self.directory_widget.text() if not directory: return unpacker = self.unpackers.checkedButton() if unpacker: record_usage(unpacker=unpacker.text()) options = self.unpacker_options.currentWidget().options() if options is None: return if handle_error( self, reprounzip.unpack(self.package_widget.text(), unpacker.unpacker, directory, options)): self.unpacked.emit(os.path.abspath(directory), options.get('root')) else: error_msg(self, "No unpacker selected", 'warning')
class RunTab(QtWidgets.QWidget): """The main window, that allows you to run/change an unpacked experiment. """ UNPACKERS = [ ('directory', DirectoryOptions), ('chroot', ChrootOptions), ('docker', DockerOptions), ('vagrant', VagrantOptions), ] directory = None unpacker = None def __init__(self, unpacked_directory='', **kwargs): super(RunTab, self).__init__(**kwargs) layout = QtWidgets.QGridLayout() layout.addWidget(QtWidgets.QLabel("Experiment directory:"), 0, 0) self.directory_widget = QtWidgets.QLineEdit(unpacked_directory) self.directory_widget.editingFinished.connect(self._directory_changed) layout.addWidget(self.directory_widget, 0, 1) browse = QtWidgets.QPushButton("Browse") browse.clicked.connect(self._browse) layout.addWidget(browse, 0, 2) layout.addWidget(QtWidgets.QLabel("Unpacker:"), 1, 0, QtCore.Qt.AlignTop) self.unpacker_widget = QtWidgets.QLabel("-") layout.addWidget(self.unpacker_widget, 1, 1, 1, 2) layout.addWidget(QtWidgets.QLabel("Input/output files:"), 2, 0, QtCore.Qt.AlignTop) self.files_button = QtWidgets.QPushButton("Manage files", enabled=False) self.files_button.clicked.connect(self._open_files_manager) layout.addWidget(self.files_button, 2, 1, 1, 2) layout.addWidget(QtWidgets.QLabel("Runs:"), 3, 0, QtCore.Qt.AlignTop) self.runs_widget = QtWidgets.QListWidget( selectionMode=QtWidgets.QListWidget.MultiSelection) layout.addWidget(self.runs_widget, 3, 1, 3, 1) select_all = QtWidgets.QPushButton("Select All") select_all.clicked.connect(self.runs_widget.selectAll) layout.addWidget(select_all, 3, 2) deselect_all = QtWidgets.QPushButton("Deselect All") deselect_all.clicked.connect(self.runs_widget.clearSelection) layout.addWidget(deselect_all, 4, 2) layout.addWidget(QtWidgets.QLabel("Elevate privileges:"), 6, 0) self.root = QtWidgets.QComboBox(editable=False) self.root.addItems(ROOT.TEXT) layout.addWidget(self.root, 6, 1, 1, 2) layout.addWidget(QtWidgets.QLabel("Jupyter integration:"), 7, 0) self.run_jupyter_notebook = QtWidgets.QCheckBox("Run notebook server", checked=False, enabled=False) layout.addWidget(self.run_jupyter_notebook, 7, 1, 1, 2) group = QtWidgets.QGroupBox(title="Unpacker options") group_layout = QtWidgets.QVBoxLayout() self.unpacker_options = ResizableStack() scroll = QtWidgets.QScrollArea(widgetResizable=True) scroll.setWidget(self.unpacker_options) group_layout.addWidget(scroll) group.setLayout(group_layout) layout.addWidget(group, 8, 0, 1, 3) layout.setRowStretch(8, 1) for i, (name, WidgetClass) in enumerate(self.UNPACKERS): widget = WidgetClass() self.unpacker_options.addWidget(widget) self.unpacker_options.addWidget( QtWidgets.QLabel("Select a directory to display options...")) self.unpacker_options.setCurrentIndex(len(self.UNPACKERS)) buttons = QtWidgets.QHBoxLayout() buttons.addStretch(1) self.run_widget = QtWidgets.QPushButton("Run experiment") self.run_widget.clicked.connect(self._run) buttons.addWidget(self.run_widget) self.destroy_widget = QtWidgets.QPushButton("Destroy unpacked " "experiment") self.destroy_widget.clicked.connect(self._destroy) buttons.addWidget(self.destroy_widget) layout.addLayout(buttons, 9, 0, 1, 3) self.setLayout(layout) self._directory_changed() def _browse(self): picked = QtWidgets.QFileDialog.getExistingDirectory( self, "Pick directory", QtCore.QDir.currentPath()) if picked: record_usage(browse_unpacked=True) self.directory_widget.setText(picked) self._directory_changed() def _directory_changed(self, new_dir=None, force=False): if not force and self.directory_widget.text() == self.directory: return self.directory = self.directory_widget.text() unpacker = reprounzip.check_directory(self.directory) self.run_jupyter_notebook.setChecked(False) self.run_jupyter_notebook.setEnabled(False) self.runs_widget.clear() if unpacker is not None: with open(self.directory + '/config.yml') as fp: self.config = yaml.safe_load(fp) self.run_widget.setEnabled(True) self.destroy_widget.setEnabled(True) self.files_button.setEnabled(True) self.unpacker = unpacker self.unpacker_widget.setText(unpacker) for run in self.config['runs']: self.runs_widget.addItem(' '.join( reprounzip.shell_escape(arg) for arg in run['argv'])) self.runs_widget.selectAll() self.unpacker_options.setCurrentIndex( dict((n, i) for i, (n, w) in enumerate(self.UNPACKERS)).get(unpacker, 4)) if (unpacker == 'docker' and reprounzip.find_command('reprozip-jupyter') is not None and reprounzip.is_jupyter(self.directory)): self.run_jupyter_notebook.setEnabled(True) self.run_jupyter_notebook.setChecked(True) else: self.run_widget.setEnabled(False) self.destroy_widget.setEnabled(False) self.files_button.setEnabled(False) self.unpacker = None self.unpacker_widget.setText("-") self.unpacker_options.setCurrentIndex(len(self.UNPACKERS)) def _run(self): options = self.unpacker_options.currentWidget().options() if options is None: return runs = sorted(i.row() for i in self.runs_widget.selectedIndexes()) if not runs: error_msg(self, "No run selected", 'warning') return record_usage(run='%d/%d' % (len(runs), self.runs_widget.count())) handle_error( self, reprounzip.run(self.directory, runs=runs, unpacker=self.unpacker, root=ROOT.INDEX_TO_OPTION[self.root.currentIndex()], jupyter=self.run_jupyter_notebook.isChecked(), **options)) def _destroy(self): handle_error( self, reprounzip.destroy( self.directory, unpacker=self.unpacker, root=ROOT.INDEX_TO_OPTION[self.root.currentIndex()])) self._directory_changed(force=True) def _open_files_manager(self): manager = FilesManager( parent=self, directory=self.directory_widget.text(), unpacker=self.unpacker, root=ROOT.INDEX_TO_OPTION[self.root.currentIndex()]) manager.exec_() def set_directory(self, directory, root=None): self.root.setCurrentIndex(ROOT.OPTION_TO_INDEX[root]) self.directory_widget.setText(directory) self._directory_changed(force=True) def should_exit(self): if self.unpacker: r = QtWidgets.QMessageBox.question( self, "Close Confirmation", "The experiment is still unpacked with '%s'. Are you sure you " "want to exit without removing it?" % self.unpacker, QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) if r == QtWidgets.QMessageBox.Yes: record_usage(leave_unpacked=True) return True else: return False else: return True def replaceable(self): return not self.unpacker
class UnpackTab(QtWidgets.QWidget): """The unpack window, that sets up a .RPZ file in a directory. """ UNPACKERS = [ ('directory', DirectoryOptions), ('chroot', ChrootOptions), ('docker', DockerOptions), ('vagrant', VagrantOptions), ] unpacked = QtCore.Signal(str, object) def __init__(self, package='', **kwargs): super(UnpackTab, self).__init__(**kwargs) layout = QtWidgets.QGridLayout() layout.addWidget(QtWidgets.QLabel("RPZ package:"), 0, 0) self.package_widget = QtWidgets.QLineEdit(package, enabled=False) layout.addWidget(self.package_widget, 0, 1) browse_pkg = QtWidgets.QPushButton("Browse") browse_pkg.clicked.connect(self._browse_pkg) layout.addWidget(browse_pkg, 0, 2) layout.addWidget(QtWidgets.QLabel("Unpacker:"), 1, 0, QtCore.Qt.AlignTop) ulayout = QtWidgets.QVBoxLayout() self.unpackers = QtWidgets.QButtonGroup() for i, name in enumerate(n for n, c in self.UNPACKERS): radio = QtWidgets.QRadioButton(name) radio.unpacker = name self.unpackers.addButton(radio, i) ulayout.addWidget(radio) layout.addLayout(ulayout, 1, 1, 1, 2) group = QtWidgets.QGroupBox(title="Unpacker options") group_layout = QtWidgets.QVBoxLayout() self.unpacker_options = ResizableStack() self.unpackers.buttonClicked[int].connect( self.unpacker_options.setCurrentIndex) scroll = QtWidgets.QScrollArea(widgetResizable=True) scroll.setWidget(self.unpacker_options) group_layout.addWidget(scroll) group.setLayout(group_layout) layout.addWidget(group, 2, 0, 1, 3) layout.setRowStretch(2, 1) for i, (name, WidgetClass) in enumerate(self.UNPACKERS): widget = WidgetClass() self.unpacker_options.addWidget(widget) self.unpacker_options.addWidget( QtWidgets.QLabel("Select an unpacker to display options...")) self.unpacker_options.setCurrentIndex(len(self.UNPACKERS)) layout.addWidget(QtWidgets.QLabel("Destination directory:"), 3, 0) self.directory_widget = QtWidgets.QLineEdit() self.directory_widget.editingFinished.connect(self._directory_changed) layout.addWidget(self.directory_widget, 3, 1) browse_dir = QtWidgets.QPushButton("Browse") browse_dir.clicked.connect(self._browse_dir) layout.addWidget(browse_dir, 3, 2) buttons = QtWidgets.QHBoxLayout() buttons.addStretch(1) self.unpack_widget = QtWidgets.QPushButton("Unpack experiment", enabled=False) self.unpack_widget.clicked.connect(self._unpack) buttons.addWidget(self.unpack_widget) layout.addLayout(buttons, 4, 0, 1, 3) self.setLayout(layout) self._package_changed() def replaceable(self): return not self.package_widget.text() def _browse_pkg(self): picked, _ = QtWidgets.QFileDialog.getOpenFileName( self, "Pick package file", QtCore.QDir.currentPath(), "ReproZip Packages (*.rpz)") if picked: record_usage(browse_pkg=True) self.package_widget.setText(picked) self._package_changed() def _package_changed(self, new_pkg=None): package = self.package_widget.text() if package.lower().endswith('.rpz'): self.directory_widget.setText(package[:-4]) self._directory_changed() def _browse_dir(self): picked, _ = QtWidgets.QFileDialog.getSaveFileName( self, "Pick directory", QtCore.QDir.currentPath()) if picked: if os.path.exists(picked): error_msg(self, "This directory already exists", 'warning') else: self.directory_widget.setText(picked) self._directory_changed() def _directory_changed(self, new_dir=None): self.unpack_widget.setEnabled(bool(self.directory_widget.text())) def _unpack(self): directory = self.directory_widget.text() if not directory: return unpacker = self.unpackers.checkedButton() if unpacker: record_usage(unpacker=unpacker.text()) options = self.unpacker_options.currentWidget().options() if options is None: return if handle_error(self, reprounzip.unpack( self.package_widget.text(), unpacker.unpacker, directory, options)): self.unpacked.emit(os.path.abspath(directory), options.get('root')) else: error_msg(self, "No unpacker selected", 'warning')
class RunTab(QtWidgets.QWidget): """The main window, that allows you to run/change an unpacked experiment. """ UNPACKERS = [ ('directory', DirectoryOptions), ('chroot', ChrootOptions), ('docker', DockerOptions), ('vagrant', VagrantOptions), ] directory = None unpacker = None def __init__(self, unpacked_directory='', **kwargs): super(RunTab, self).__init__(**kwargs) layout = QtWidgets.QGridLayout() layout.addWidget(QtWidgets.QLabel("Experiment directory:"), 0, 0) self.directory_widget = QtWidgets.QLineEdit(unpacked_directory) self.directory_widget.editingFinished.connect(self._directory_changed) layout.addWidget(self.directory_widget, 0, 1) browse = QtWidgets.QPushButton("Browse") browse.clicked.connect(self._browse) layout.addWidget(browse, 0, 2) layout.addWidget(QtWidgets.QLabel("Unpacker:"), 1, 0, QtCore.Qt.AlignTop) self.unpacker_widget = QtWidgets.QLabel("-") layout.addWidget(self.unpacker_widget, 1, 1, 1, 2) layout.addWidget(QtWidgets.QLabel("Input/output files:"), 2, 0, QtCore.Qt.AlignTop) self.files_button = QtWidgets.QPushButton("Manage files", enabled=False) self.files_button.clicked.connect(self._open_files_manager) layout.addWidget(self.files_button, 2, 1, 1, 2) layout.addWidget(QtWidgets.QLabel("Runs:"), 3, 0, QtCore.Qt.AlignTop) self.runs_widget = QtWidgets.QListWidget( selectionMode=QtWidgets.QListWidget.MultiSelection) layout.addWidget(self.runs_widget, 3, 1, 3, 1) select_all = QtWidgets.QPushButton("Select All") select_all.clicked.connect(self.runs_widget.selectAll) layout.addWidget(select_all, 3, 2) deselect_all = QtWidgets.QPushButton("Deselect All") deselect_all.clicked.connect(self.runs_widget.clearSelection) layout.addWidget(deselect_all, 4, 2) layout.addWidget(QtWidgets.QLabel("Elevate privileges:"), 6, 0) self.root = QtWidgets.QComboBox(editable=False) self.root.addItems(ROOT.TEXT) layout.addWidget(self.root, 6, 1, 1, 2) layout.addWidget(QtWidgets.QLabel("Jupyter integration:"), 7, 0) self.run_jupyter_notebook = QtWidgets.QCheckBox("Run notebook server", checked=False, enabled=False) layout.addWidget(self.run_jupyter_notebook, 7, 1, 1, 2) group = QtWidgets.QGroupBox(title="Unpacker options") group_layout = QtWidgets.QVBoxLayout() self.unpacker_options = ResizableStack() scroll = QtWidgets.QScrollArea(widgetResizable=True) scroll.setWidget(self.unpacker_options) group_layout.addWidget(scroll) group.setLayout(group_layout) layout.addWidget(group, 8, 0, 1, 3) layout.setRowStretch(8, 1) for i, (name, WidgetClass) in enumerate(self.UNPACKERS): widget = WidgetClass() self.unpacker_options.addWidget(widget) self.unpacker_options.addWidget( QtWidgets.QLabel("Select a directory to display options...")) self.unpacker_options.setCurrentIndex(len(self.UNPACKERS)) buttons = QtWidgets.QHBoxLayout() buttons.addStretch(1) self.run_widget = QtWidgets.QPushButton("Run experiment") self.run_widget.clicked.connect(self._run) buttons.addWidget(self.run_widget) self.destroy_widget = QtWidgets.QPushButton("Destroy unpacked " "experiment") self.destroy_widget.clicked.connect(self._destroy) buttons.addWidget(self.destroy_widget) layout.addLayout(buttons, 9, 0, 1, 3) self.setLayout(layout) self._directory_changed() def _browse(self): picked = QtWidgets.QFileDialog.getExistingDirectory( self, "Pick directory", QtCore.QDir.currentPath()) if picked: record_usage(browse_unpacked=True) self.directory_widget.setText(picked) self._directory_changed() def _directory_changed(self, new_dir=None, force=False): if not force and self.directory_widget.text() == self.directory: return self.directory = self.directory_widget.text() unpacker = reprounzip.check_directory(self.directory) self.run_jupyter_notebook.setChecked(False) self.run_jupyter_notebook.setEnabled(False) self.runs_widget.clear() if unpacker is not None: with open(self.directory + '/config.yml') as fp: self.config = yaml.safe_load(fp) self.run_widget.setEnabled(True) self.destroy_widget.setEnabled(True) self.files_button.setEnabled(True) self.unpacker = unpacker self.unpacker_widget.setText(unpacker) for run in self.config['runs']: self.runs_widget.addItem(' '.join(reprounzip.shell_escape(arg) for arg in run['argv'])) self.runs_widget.selectAll() self.unpacker_options.setCurrentIndex( dict((n, i) for i, (n, w) in enumerate(self.UNPACKERS)) .get(unpacker, 4)) if (unpacker == 'docker' and reprounzip.find_command('reprozip-jupyter') is not None and reprounzip.is_jupyter(self.directory)): self.run_jupyter_notebook.setEnabled(True) self.run_jupyter_notebook.setChecked(True) else: self.run_widget.setEnabled(False) self.destroy_widget.setEnabled(False) self.files_button.setEnabled(False) self.unpacker = None self.unpacker_widget.setText("-") self.unpacker_options.setCurrentIndex(len(self.UNPACKERS)) def _run(self): options = self.unpacker_options.currentWidget().options() if options is None: return runs = sorted(i.row() for i in self.runs_widget.selectedIndexes()) if not runs: error_msg(self, "No run selected", 'warning') return record_usage(run='%d/%d' % (len(runs), self.runs_widget.count())) handle_error(self, reprounzip.run( self.directory, runs=runs, unpacker=self.unpacker, root=ROOT.INDEX_TO_OPTION[self.root.currentIndex()], jupyter=self.run_jupyter_notebook.isChecked(), **options)) def _destroy(self): handle_error(self, reprounzip.destroy( self.directory, unpacker=self.unpacker, root=ROOT.INDEX_TO_OPTION[self.root.currentIndex()])) self._directory_changed(force=True) def _open_files_manager(self): manager = FilesManager( parent=self, directory=self.directory_widget.text(), unpacker=self.unpacker, root=ROOT.INDEX_TO_OPTION[self.root.currentIndex()]) manager.exec_() def set_directory(self, directory, root=None): self.root.setCurrentIndex(ROOT.OPTION_TO_INDEX[root]) self.directory_widget.setText(directory) self._directory_changed(force=True) def should_exit(self): if self.unpacker: r = QtWidgets.QMessageBox.question( self, "Close Confirmation", "The experiment is still unpacked with '%s'. Are you sure you " "want to exit without removing it?" % self.unpacker, QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) if r == QtWidgets.QMessageBox.Yes: record_usage(leave_unpacked=True) return True else: return False else: return True def replaceable(self): return not self.unpacker