def linux_try_register_default(self, window): rcpath = os.path.expanduser('~/.reprozip') rcname = 'rpuzqt-nodefault' if os.path.exists(os.path.join(rcpath, rcname)): logger.info("Registering application disabled") return try: proc = subprocess.Popen(['xdg-mime', 'query', 'default', 'application/x-reprozip'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() registered = bool(out.strip()) except OSError: record_usage(appregister='fail xdg-mime') logger.info("xdg-mime call failed, not registering application") else: if not registered: r = QtWidgets.QMessageBox.question( window, "Default application", "Do you want to set ReproUnzip as the default to open " ".rpz files?", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) if r == QtWidgets.QMessageBox.Yes: self.linux_register_default(window) elif r == QtWidgets.QMessageBox.No: record_usage(appregister='no') if not os.path.exists(rcpath): os.mkdir(rcpath) with open(os.path.join(rcpath, rcname), 'w') as fp: fp.write('1\n')
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 linux_try_register_default(self, window): rcpath = os.path.expanduser('~/.reprozip') rcname = 'rpuzqt-nodefault' if os.path.exists(os.path.join(rcpath, rcname)): logger.info("Registering application disabled") return try: proc = subprocess.Popen(['xdg-mime', 'query', 'default', 'application/x-reprozip'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() registered = bool(out.strip()) except OSError: record_usage(appregister='fail xdg-mime') logger.info("xdg-mime call failed, not registering application") else: if not registered: r = QtGui.QMessageBox.question( window, "Default application", "Do you want to set ReproUnzip as the default to open " ".rpz files?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) if r == QtGui.QMessageBox.Yes: self.linux_register_default(window) elif r == QtGui.QMessageBox.No: record_usage(appregister='no') if not os.path.exists(rcpath): os.mkdir(rcpath) with open(os.path.join(rcpath, rcname), 'w') as fp: fp.write('1\n')
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 _reset(self): selected = self.files_widget.selectedIndexes()[0].row() file_status = self.files_status[selected] record_usage(file_reset=True) handle_error(self, reprounzip.upload( self.directory, file_status.name, None, unpacker=self.unpacker, root=self.root)) self._file_changed()
def _download(self): selected = self.files_widget.selectedIndexes()[0].row() file_status = self.files_status[selected] picked, _ = QtWidgets.QFileDialog.getSaveFileName( self, "Pick destination", QtCore.QDir.currentPath() + '/' + file_status.name) if picked: record_usage(file_download=True) handle_error(self, reprounzip.download( self.directory, file_status.name, picked, unpacker=self.unpacker, root=self.root)) self._file_changed()
def _upload(self): selected = self.files_widget.selectedIndexes()[0].row() file_status = self.files_status[selected] picked, _ = QtWidgets.QFileDialog.getOpenFileName( self, "Pick file to upload", QtCore.QDir.currentPath()) if picked: record_usage(file_upload=True) handle_error(self, reprounzip.upload( self.directory, file_status.name, picked, unpacker=self.unpacker, root=self.root)) self._file_changed()
def options(self): options = super(VagrantOptions, self).options() ports = parse_ports(self.ports.text(), self) if ports is None: return None for host, container, proto in parse_ports(self.ports.text(), self): options['args'].append('--expose-port=%s:%s/%s' % (host, container, proto)) record_usage(vagrant_run_port_fwd=bool(ports)) return options
def _reset(self): selected = self.files_widget.selectedIndexes()[0].row() file_status = self.files_status[selected] record_usage(file_reset=True) handle_error( self, reprounzip.upload(self.directory, file_status.name, None, unpacker=self.unpacker, root=self.root)) self._file_changed()
def should_exit(self): if self.unpacker: r = QtGui.QMessageBox.question( self, "Close Confirmation", "The experiment is still unpacked with '%s'. Are you sure you " "want to exit without removing it?" % self.unpacker, QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) if r == QtGui.QMessageBox.Yes: record_usage(leave_unpacked=True) else: return False else: return True
def options(self): options = super(DockerOptions, self).options() if self.machine.currentIndex() != -1: options['docker-machine'] = self.machine.itemData( self.machine.currentIndex()) record_usage( use_docker_machine=options['docker-machine'] is not None) options['root'] = ROOT.INDEX_TO_OPTION[self.root.currentIndex()] if self.image.text(): options['args'].extend(['--base-image', self.image.text()]) record_usage(docker_base_image=True) if self.distribution.text(): options['args'].extend(['--distribution', self.distribution.text()]) record_usage(docker_distribution=True) if self.install_pkgs.isChecked(): options['args'].append('--install-pkgs') record_usage(root=options['root'], docker_install_pkgs=self.install_pkgs.isChecked()) return options
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 options(self): options = super(DockerOptions, self).options() if self.machine.currentIndex() != -1: options['docker-machine'] = self.machine.itemData( self.machine.currentIndex()) record_usage( use_docker_machine=options['docker-machine'] is not None) options['root'] = ROOT.INDEX_TO_OPTION[self.root.currentIndex()] if self.image.text(): options['args'].extend(['--base-image', self.image.text()]) record_usage(docker_base_image=True) if self.distribution.text(): options['args'].extend( ['--distribution', self.distribution.text()]) record_usage(docker_distribution=True) if self.install_pkgs.isChecked(): options['args'].append('--install-pkgs') record_usage(root=options['root'], docker_install_pkgs=self.install_pkgs.isChecked()) return options
def event(self, event): if event.type() == QtCore.QEvent.FileOpen: record_usage(fileopenevent=True) # Create new window for this RPZ window = ReprounzipUi(unpack=dict(package=event.file())) window.setVisible(True) self.windows.add(window) # Close first window if it exists if self.first_window and self.first_window.replaceable(): self.first_window.close() self.first_window.deleteLater() self.first_window = None return True return QtGui.QApplication.event(self, event)
def options(self): options = super(DockerOptions, self).options() if self.tunneled_x11.isChecked(): options['args'].append('--tunneled-x11') record_usage(docker_tunneled_x11=True) if self.detach.isChecked(): options['args'].append('--detach') record_usage(docker_detach=True) nb_raw = 0 for opt in self.raw_options.text().split(): opt = opt.strip() if opt: nb_raw += 1 options['args'].append('--docker-option=%s' % opt) if nb_raw: record_usage(docker_raw_options=nb_raw) ports = parse_ports(self.ports.text(), self) if ports is None: return None for host, container, proto in ports: options['args'].extend([ '--docker-option=-p', '--docker-option=%s:%s/%s' % (host, container, proto) ]) record_usage(docker_run_port_fwd=bool(ports)) return options
def event(self, event): if event.type() == QtCore.QEvent.FileOpen: record_usage(fileopenevent=True) # Create new window for this RPZ window = ReprounzipUi(unpack=dict(package=event.file())) window.setVisible(True) self.windows.add(window) # Close first window if it exists if self.first_window and self.first_window.replaceable(): self.first_window.close() self.first_window.deleteLater() self.first_window = None return True return QtWidgets.QApplication.event(self, event)
def options(self): options = super(DockerOptions, self).options() if self.tunneled_x11.isChecked(): options['args'].append('--tunneled-x11') record_usage(docker_tunneled_x11=True) if self.detach.isChecked(): options['args'].append('--detach') record_usage(docker_detach=True) nb_raw = 0 for opt in self.raw_options.text().split(): opt = opt.strip() if opt: nb_raw += 1 options['args'].append('--docker-option=%s' % opt) if nb_raw: record_usage(docker_raw_options=nb_raw) ports = parse_ports(self.ports.text(), self) if ports is None: return None for host, container, proto in ports: options['args'].extend( ['--docker-option=-p', '--docker-option=%s:%s/%s' % (host, container, proto)]) record_usage(docker_run_port_fwd=bool(ports)) return options
def _upload(self): selected = self.files_widget.selectedIndexes()[0].row() file_status = self.files_status[selected] picked, _ = QtWidgets.QFileDialog.getOpenFileName( self, "Pick file to upload", QtCore.QDir.currentPath()) if picked: record_usage(file_upload=True) handle_error( self, reprounzip.upload(self.directory, file_status.name, picked, unpacker=self.unpacker, root=self.root)) self._file_changed()
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 _download(self): selected = self.files_widget.selectedIndexes()[0].row() file_status = self.files_status[selected] picked, _ = QtWidgets.QFileDialog.getSaveFileName( self, "Pick destination", QtCore.QDir.currentPath() + '/' + file_status.name) if picked: record_usage(file_download=True) handle_error( self, reprounzip.download(self.directory, file_status.name, picked, unpacker=self.unpacker, root=self.root)) self._file_changed()
def __init__(self, directory, unpacker=None, root=None, **kwargs): super(FilesManager, self).__init__(**kwargs) self.directory = directory self.unpacker = unpacker self.root = root layout = QtWidgets.QHBoxLayout() self.files_widget = QtWidgets.QListWidget( selectionMode=QtWidgets.QListWidget.SingleSelection) self.files_widget.itemSelectionChanged.connect(self._file_changed) layout.addWidget(self.files_widget) right_layout = QtWidgets.QGridLayout() right_layout.addWidget(QtWidgets.QLabel("name:"), 0, 0) self.f_name = QtWidgets.QLineEdit('', readOnly=True) right_layout.addWidget(self.f_name, 0, 1) right_layout.addWidget(QtWidgets.QLabel("Path:"), 1, 0) self.f_path = QtWidgets.QLineEdit('', readOnly=True) right_layout.addWidget(self.f_path, 1, 1) right_layout.addWidget(QtWidgets.QLabel("Current:"), 2, 0) self.f_status = QtWidgets.QLineEdit('', readOnly=True) right_layout.addWidget(self.f_status, 2, 1) self.b_upload = QtWidgets.QPushButton("Upload a replacement", enabled=False) self.b_upload.clicked.connect(self._upload) right_layout.addWidget(self.b_upload, 3, 0, 1, 2) self.b_download = QtWidgets.QPushButton("Download to disk", enabled=False) self.b_download.clicked.connect(self._download) right_layout.addWidget(self.b_download, 4, 0, 1, 2) self.b_reset = QtWidgets.QPushButton("Reset file", enabled=False) self.b_reset.clicked.connect(self._reset) right_layout.addWidget(self.b_reset, 5, 0, 1, 2) right_layout.setRowStretch(6, 1) layout.addLayout(right_layout) self.setLayout(layout) self.files_status = reprounzip.FilesStatus(directory) for file_status in self.files_status: text = "[%s%s] %s" % (("I" if file_status.is_input else ''), ("O" if file_status.is_output else ''), file_status.name) self.files_widget.addItem(text) record_usage(iofiles=self.files_widget.count())
def __init__(self, directory, unpacker=None, root=None, **kwargs): super(FilesManager, self).__init__(**kwargs) self.directory = directory self.unpacker = unpacker self.root = root layout = QtWidgets.QHBoxLayout() self.files_widget = QtWidgets.QListWidget( selectionMode=QtWidgets.QListWidget.SingleSelection) self.files_widget.itemSelectionChanged.connect(self._file_changed) layout.addWidget(self.files_widget) right_layout = QtWidgets.QGridLayout() right_layout.addWidget(QtWidgets.QLabel("name:"), 0, 0) self.f_name = QtWidgets.QLineEdit('', readOnly=True) right_layout.addWidget(self.f_name, 0, 1) right_layout.addWidget(QtWidgets.QLabel("Path:"), 1, 0) self.f_path = QtWidgets.QLineEdit('', readOnly=True) right_layout.addWidget(self.f_path, 1, 1) right_layout.addWidget(QtWidgets.QLabel("Current:"), 2, 0) self.f_status = QtWidgets.QLineEdit('', readOnly=True) right_layout.addWidget(self.f_status, 2, 1) self.b_upload = QtWidgets.QPushButton("Upload a replacement", enabled=False) self.b_upload.clicked.connect(self._upload) right_layout.addWidget(self.b_upload, 3, 0, 1, 2) self.b_download = QtWidgets.QPushButton("Download to disk", enabled=False) self.b_download.clicked.connect(self._download) right_layout.addWidget(self.b_download, 4, 0, 1, 2) self.b_reset = QtWidgets.QPushButton("Reset file", enabled=False) self.b_reset.clicked.connect(self._reset) right_layout.addWidget(self.b_reset, 5, 0, 1, 2) right_layout.setRowStretch(6, 1) layout.addLayout(right_layout) self.setLayout(layout) self.files_status = reprounzip.FilesStatus(directory) for file_status in self.files_status: text = "[%s%s] %s" % ( ("I" if file_status.is_input else ''), ("O" if file_status.is_output else ''), file_status.name) self.files_widget.addItem(text) record_usage(iofiles=self.files_widget.count())
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 _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')
def options(self): options = super(ChrootOptions, self).options() options['root'] = ROOT.INDEX_TO_OPTION[self.root.currentIndex()] if self.preserve_owner.checkState() == QtCore.Qt.Unchecked: options['args'].append('--dont-preserve-owner') elif self.preserve_owner.checkState() == QtCore.Qt.Checked: options['args'].append('--preserve-owner') if self.magic_dirs.checkState() == QtCore.Qt.Unchecked: options['args'].append('--dont-bind-magic-dirs') elif self.magic_dirs.checkState() == QtCore.Qt.Checked: options['args'].append('--bind-magic-dirs') record_usage(chroot_preserve_owner=self.preserve_owner.checkState(), chroot_magic_dirs=self.magic_dirs.checkState()) return options
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')
def options(self): options = super(ChrootOptions, self).options() options['root'] = ROOT.INDEX_TO_OPTION[self.root.currentIndex()] if self.preserve_owner.checkState() == QtCore.Qt.Unchecked: options['args'].append('--dont-preserve-owner') elif self.preserve_owner.checkState() == QtCore.Qt.Checked: options['args'].append('--preserve-owner') if self.magic_dirs.checkState() == QtCore.Qt.Unchecked: options['args'].append('--dont-bind-magic-dirs') elif self.magic_dirs.checkState() == QtCore.Qt.Checked: options['args'].append('--bind-magic-dirs') record_usage( chroot_preserve_owner=self.preserve_owner.checkState(), chroot_magic_dirs=self.magic_dirs.checkState()) return options
def __init__(self): super(DockerOptions, self).__init__() self.root = QtWidgets.QComboBox(editable=False) self.root.addItems(ROOT.TEXT) self.add_row("Elevate privileges:", self.root) try: cmd = ['docker-machine', 'ls', '-q'] query = subprocess.Popen(cmd, stdout=subprocess.PIPE) out, _ = query.communicate() if query.returncode != 0: raise subprocess.CalledProcessError(query.returncode, cmd) self.machine = QtWidgets.QComboBox(editable=False) if 'DOCKER_HOST' in os.environ: self.machine.addItem("Custom config from environment", None) else: self.machine.addItem("Default (no machine)", None) nb_machines = 0 for machine in out.splitlines(): machine = machine.strip() if machine: self.machine.addItem(machine.decode('utf-8', 'replace'), machine) nb_machines += 1 record_usage(docker_machines=nb_machines) except (OSError, subprocess.CalledProcessError): self.machine = QtWidgets.QComboBox(editable=False, enabled=False) self.machine.addItem("docker-machine unavailable", None) record_usage(docker_machines=False) self.add_row("docker-machine:", self.machine) self.image = QtWidgets.QLineEdit(placeholderText='detect') self.add_row("Base image:", self.image) self.distribution = QtWidgets.QLineEdit(placeholderText='detect') self.add_row("Distribution:", self.distribution) self.install_pkgs = QtWidgets.QCheckBox("install packages rather than " "extracting them from RPZ") self.add_row("Install packages:", self.install_pkgs)
def main(): """Entry point when called on the command-line. """ # Locale locale.setlocale(locale.LC_ALL, '') parser = argparse.ArgumentParser( description="Graphical user interface for reprounzip", epilog="Please report issues to [email protected]") parser.add_argument('--version', action='version', version="reprounzip-qt version %s" % __version__) parser.add_argument('-v', '--verbose', action='count', default=1, dest='verbosity', help="augments verbosity level") parser.add_argument('package', nargs=argparse.OPTIONAL) parser.add_argument('--unpacked', action='append', default=[]) argv = sys.argv[1:] i = 0 while i < len(argv): if argv[i].startswith('-psn'): del argv[i] else: i += 1 args = parser.parse_args(argv) setup_logging('REPROUNZIP-QT', args.verbosity) from reprounzip_qt.gui import Application, ReprounzipUi app = Application(sys.argv) window_args = {} if args.package and args.unpacked: sys.stderr.write("You can't pass both a package and a unpacked " "directory\n") sys.exit(2) elif args.package: logger.info("Got package on the command-line: %s", args.package) record_usage(cmdline='package') window_args = dict(unpack=dict(package=args.package)) elif len(args.unpacked) == 1: logger.info("Got unpacked directory on the command-line: %s", args.unpacked) record_usage(cmdline='directory') window_args = dict(run=dict(unpacked_directory=args.unpacked[0]), tab=1) elif args.unpacked: sys.stderr.write("You may only use --unpacked once\n") sys.exit(2) else: record_usage(cmdline='empty') window = ReprounzipUi(**window_args) app.set_first_window(window) window.setVisible(True) app.exec_() submit_usage_report() sys.exit(0)
def linux_register_default(self, window): record_usage(appregister='yes') command = os.path.abspath(sys.argv[0]) if not os.path.isfile(command): logger.error("Couldn't find argv[0] location!") return dirname = tempfile.mkdtemp(prefix='reprozip_mime_') try: # Install x-reprozip mimetype logger.info("Installing application/x-reprozip mimetype for .rpz") filename = os.path.join(dirname, 'nyuvida-reprozip.xml') with open(filename, 'w') as fp: fp.write('''\ <?xml version="1.0"?> <mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info"> <mime-type type="application/x-reprozip"> <comment>ReproZip Package</comment> <glob pattern="*.rpz"/> </mime-type> </mime-info> ''') subprocess.check_call(['xdg-mime', 'install', filename]) subprocess.check_call(['update-mime-database', os.path.join(os.environ['HOME'], '.local/share/mime')]) # Install icon logger.info("Copying icon") icon_dest_root = os.path.join(os.environ['HOME'], '.local/share/icons/hicolor') icon_dest_subdir = os.path.join(icon_dest_root, '48x48/mimetypes') icon_dest_file = os.path.join(icon_dest_subdir, 'application-x-reprozip.png') icon_src = os.path.join(os.path.dirname(reprounzip_qt.__file__), 'icon.png') if not os.path.exists(icon_dest_subdir): os.makedirs(icon_dest_subdir) shutil.copyfile(icon_src, icon_dest_file) subprocess.check_call(['update-icon-caches', icon_dest_root]) # Install desktop file logger.info("Installing reprounzip.desktop file") app_dir = os.path.join(os.environ['HOME'], '.local/share/applications') if not os.path.exists(app_dir): os.makedirs(app_dir) with open(os.path.join(app_dir, 'reprounzip.desktop'), 'w') as fp: fp.write('''\ [Desktop Entry] Name=ReproUnzip Exec={0} %f Type=Application MimeType=application/x-reprozip Icon={1} '''.format(command, icon_dest_file)) subprocess.check_call(['update-desktop-database', app_dir]) logger.info("Application registered!") except (OSError, subprocess.CalledProcessError): error_msg(window, "Error setting default application", 'error', traceback.format_exc()) finally: shutil.rmtree(dirname)
def options(self): options = super(VagrantOptions, self).options() if self.image.text(): options['args'].extend(['--base-image', self.image.text()]) record_usage(vagrant_base_image=True) if self.distribution.text(): options['args'].extend( ['--distribution', self.distribution.text()]) record_usage(vagrant_distribution=True) if self.memory.value() != 99: options['args'].extend(['--memory', '%d' % self.memory.value()]) record_usage(vagrant_memory=self.memory.value()) if self.gui.isChecked(): options['args'].append('--use-gui') record_usage(vagrant_gui=True) ports = parse_ports(self.ports.text(), self) if ports is None: return None record_usage(vagrant_unpack_port_fwd=bool(ports)) for host, container, proto in ports: options['args'].append('--expose-port=%s:%s/%s' % (host, container, proto)) if not self.use_chroot.isChecked(): options['args'].append('--dont-use-chroot') record_usage(vagrant_no_chroot=True) if not self.magic_dirs.isChecked(): options['args'].append('--dont-bind-magic-dirs') record_usage(vagrant_magic_dirs=False) return options
def options(self): options = super(VagrantOptions, self).options() if self.image.text(): options['args'].extend(['--base-image', self.image.text()]) record_usage(vagrant_base_image=True) if self.distribution.text(): options['args'].extend(['--distribution', self.distribution.text()]) record_usage(vagrant_distribution=True) if self.memory.value() != 99: options['args'].extend(['--memory', '%d' % self.memory.value()]) record_usage(vagrant_memory=self.memory.value()) if self.gui.isChecked(): options['args'].append('--use-gui') record_usage(vagrant_gui=True) ports = parse_ports(self.ports.text(), self) if ports is None: return None record_usage(vagrant_unpack_port_fwd=bool(ports)) for host, container, proto in ports: options['args'].append('--expose-port=%s:%s/%s' % ( host, container, proto)) if not self.use_chroot.isChecked(): options['args'].append('--dont-use-chroot') record_usage(vagrant_no_chroot=True) if not self.magic_dirs.isChecked(): options['args'].append('--dont-bind-magic-dirs') record_usage(vagrant_magic_dirs=False) return options