예제 #1
0
class PylouApplet(Applet):

    """Main Applet containing the UI of Pylou."""

    def __init__(self, parent, args=None):
        """Init class."""
        Applet.__init__(self, parent)

    def init(self):
        """Start the Applet."""
        self._widget = None
        self.setHasConfigurationInterface(True)
        self.setAspectRatioMode(Plasma.IgnoreAspectRatio)
        self.configurations = self.config()
        self._widget = PylouWidget(self)
        self._widget.init()
        self.setGraphicsWidget(self._widget)
        self.applet.setPassivePopup(True)
        self.setPopupIcon(QIcon.fromTheme("edit-find"))
        # for some odd reason this has to be called twice?
        self.setGraphicsWidget(self._widget)
        self.prepareConfigDialog()

    def update_db(self):
        """Update the DB."""
        return call("kdesudo --noignorebutton -c updatedb", shell=True)

    def prepareConfigDialog(self):
        """Prepare the Configuration Dialog."""
        self.bcolor, self.dialog = QColor(), KDialog()
        self.dialog.setWindowTitle(__package__ + "Settings")
        self.layBox = QGridLayout(self.dialog.mainWidget())
        self.title = KTitleWidget(self.dialog)
        self.title.setText(__doc__ + " !")
        self.title.setAutoHideTimeout(3000)
        self.FontButton = KFontRequester(self.dialog)
        self.tfont = QFont(QVariant(self.configurations.readEntry("TextFont",
                           QVariant(QFont()))))
        self.FontButton.setFont(self.tfont)
        self.ColorButton = KColorButton(self.dialog)
        self.tcolor = QColor(self.configurations.readEntry("TextColor",
                             QColor("#000").name()))
        self.ColorButton.setColor(self.tcolor)
        self.BColorButton = KColorButton(self.dialog)
        # button to update the DB via sudo updatedb

        self.UpdateDB = KPushButton("Update Database", self.dialog,
                                    clicked=lambda: self.update_db())
        self.UpdateDB.setToolTip("Database is Updated every Reboot and Daily!")
        self.Histor = KPushButton("Delete my History", self.dialog,
                                  clicked=delete_my_history)
        self.Histor.setToolTip("History is Deleted every Reboot !")
        # list of banned words separated by spaces
        self.banned = KTextEdit(self.dialog)
        self.banned.setPlainText(self.configurations.readEntry(
            "Banned", "sex p**n drugs suicide decapitate religion").toString())
        # set the colors
        cg = KConfig("kdeglobals")
        color = cg.group("Colors:View").readEntry(
            "BackgroundAlternate").split(",")
        self.bcolor = QColor(int(color[0]), int(color[1]), int(color[2]))
        self.BColorButton.setColor(self.bcolor)
        self.history_file_path_field = KLineEdit(HISTORY_FILE_PATH)
        self.history_file_path_field.setDisabled(True)
        self.python_file_path_field = KLineEdit(__file__)
        self.python_file_path_field.setDisabled(True)
        self.kill_baloo = QCheckBox("Disable Baloo")
        self.kill_baloo.setToolTip("Enable/Disable Desktop Search Indexing")
        self.kill_baloo.stateChanged.connect(lambda: call(
            DISABLE_BALOO_CMD.format(str(
                not self.kill_baloo.isChecked()).lower()), shell=True))
        self.kill_baloo.stateChanged.connect(lambda: QMessageBox.information(
            self.dialog, __doc__, """
            <b>Indexing Disabled, Baloo is Dead !
            """ if self.kill_baloo.isChecked() else """
            <b>Indexing Enabled, Baloo is Running !"""))
        self.updatez = KPushButton("Check for Updates", self.dialog,
                                   clicked=lambda: self.check_for_updates())
        self.updatez.setToolTip("Check for Pylou updates from the internet")
        self.home_sweet_home = QCheckBox("Only Search Home")
        self.home_sweet_home.setToolTip("Only Search on my Home folders")
        self.home_sweet_home.setChecked(
            bool(self.configurations.readEntry("Home", True)))
        # pack all widgets
        self.layBox.addWidget(self.title, 0, 1)
        self.layBox.addWidget(QLabel("Font"), 1, 0)
        self.layBox.addWidget(self.FontButton, 1, 1)
        self.layBox.addWidget(QLabel("Text Color"), 2, 0)
        self.layBox.addWidget(self.ColorButton, 2, 1)
        self.layBox.addWidget(QLabel("Alternate Color"), 3, 0)
        self.layBox.addWidget(self.BColorButton, 3, 1)
        self.layBox.addWidget(QLabel(), 4, 0)
        self.layBox.addWidget(QLabel("Mainteniance"), 5, 0)
        self.layBox.addWidget(self.UpdateDB, 5, 1)
        self.layBox.addWidget(QLabel("Privacy"), 6, 0)
        self.layBox.addWidget(self.Histor, 6, 1)
        self.layBox.addWidget(QLabel("History file"), 7, 0)
        self.layBox.addWidget(self.history_file_path_field, 7, 1)
        self.layBox.addWidget(QLabel(__package__ + "file"), 8, 0)
        self.layBox.addWidget(self.python_file_path_field, 8, 1)
        self.layBox.addWidget(QLabel("Banned Words"), 9, 0)
        self.layBox.addWidget(self.banned, 9, 1)
        self.layBox.addWidget(QLabel("SelfUpdating"), 10, 0)
        self.layBox.addWidget(self.updatez, 10, 1)
        self.layBox.addWidget(QLabel("<b>Disable Indexing"), 12, 0)
        self.layBox.addWidget(self.kill_baloo, 12, 1)
        self.layBox.addWidget(QLabel("Search Paths"), 13, 0)
        self.layBox.addWidget(self.home_sweet_home, 13, 1)
        # button box on the bottom
        self.dialog.setButtons(KDialog.ButtonCodes(
            KDialog.ButtonCode(KDialog.Ok | KDialog.Cancel | KDialog.Apply)))
        # connect
        self.dialog.applyClicked.connect(self.configAccepted)
        self.dialog.okClicked.connect(self.configAccepted)

    @pyqtSignature("configAccepted()")
    def configAccepted(self):
        """Save configuration settings."""
        self.tcolor = self.ColorButton.color()
        self.bcolor = self.BColorButton.color()
        self._widget.treeview.nativeWidget().setFont(self.tfont)
        self._widget.treeview.nativeWidget().setStyleSheet(
            "color:{};alternate-background-color:{}".format(
                self.tcolor.name(), self.bcolor.name()))
        self.configurations.writeEntry("TextColor", self.tcolor.name())
        self.configurations.writeEntry("AlternateBColor", self.bcolor.name())
        self.configurations.writeEntry("TextFont", QVariant(self.tfont))
        self.configurations.writeEntry("Banned", self.banned.toPlainText())
        self.configurations.writeEntry("Home",
                                       self.home_sweet_home.isChecked())

    def showConfigurationInterface(self):
        """Show configuration dialog."""
        self.dialog.show()
        self.dialog.raise_()

    def check_for_updates(self):
        """Method to check for updates from Git repo versus this version."""
        this_version = str(open(__file__).read())
        last_version = str(urlopen(__source__).read())
        if this_version != last_version:
            m = "Theres new Version available!<br>Download update from the web"
        else:
            m = "No new updates!<br>You have the lastest version of this app!."
        return QMessageBox.information(None, __doc__.title(), "<b>" + m)
class Main(plugin.Plugin):
    ' main class for plugin '
    def initialize(self, *args, **kwargs):
        ' class init '
        super(Main, self).initialize(*args, **kwargs)
        self.process = QProcess()
        self.process.readyReadStandardOutput.connect(self.readOutput)
        self.process.readyReadStandardError.connect(self.readErrors)
        self.process.finished.connect(self._process_finished)
        self.process.error.connect(self._process_finished)
        # directory auto completer
        self.completer, self.dirs = QCompleter(self), QDirModel(self)
        self.dirs.setFilter(QDir.Dirs | QDir.NoDotAndDotDot)
        self.completer.setModel(self.dirs)
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setCompletionMode(QCompleter.PopupCompletion)
        # menu
        menu = QMenu('VirtualEnv')
        menu.addAction('Make VirtualEnv here', lambda: self.make_virtualenv())
        self.locator.get_service('explorer').add_project_menu(menu, lang='all')

        self.group1 = QGroupBox()
        self.group1.setTitle(' Paths ')
        self.outdir = QLineEdit(path.expanduser("~"))
        self.outdir.setPlaceholderText('Target Directory for Virtualenv files')
        self.outdir.setCompleter(self.completer)
        self.btn1 = QPushButton(QIcon.fromTheme("document-open"), ' Open ')
        self.btn1.clicked.connect(lambda: self.outdir.setText(str(
            QFileDialog.getExistingDirectory(self.dock,
            'Please, Open a Target Directory for the Python VirtualEnv...',
            path.expanduser("~")))))
        self.srcdir, self.prefx = QLineEdit(), QLineEdit()
        self.srcdir.setPlaceholderText(
                    'Extra search path to look for setuptools/distribute/pip')
        self.srcdir.setToolTip('''
        Specify Extra search path to look for setuptools/distribute/pip.
        Defaults to Empty, then the setting is ignored.Defaults are OK.''')
        self.srcdir.setCompleter(self.completer)
        self.btn2 = QPushButton(QIcon.fromTheme("document-open"), ' Open ')
        self.btn2.setToolTip(
            'Specify Extra search path to look for setuptools/distribute/pip')
        self.btn2.clicked.connect(lambda: self.srcdir.setText(str(
            QFileDialog.getExistingDirectory(self.dock,
            'Please, Open a Extra search path to look for setuptools/pip...',
            path.expanduser("~")))))
        self.prefx.setPlaceholderText('Prompt prefix for this environment')
        self.prefx.setToolTip('''
        Specify a custom alternative prompt prefix for this environment.
        Defaults to Empty,this is optional,short prefix are recommended.''')
        self.btn3 = QPushButton(QIcon.fromTheme("face-smile-big"), 'Suggestion')
        self.btn3.setToolTip('Suggest me a Random CLI prompt prefix !')
        self.btn3.clicked.connect(lambda: self.prefx.setText(choice((getuser(),
        'tesla', 'einstein', 'turing', 'ritchie', 'darwin', 'curie', 'planck',
        'lovelace', 'dijsktra', 'galileo', 'schroedinger', 'perlman', 'hopper',
        'newton', 'pasteur', 'maxwell', 'aristotle‎', 'volta', 'mendelev',
        'bohr', 'crick', 'watson', 'archimedes', 'nash', 'fermi', 'dirac',
        'feynman', 'kepler', 'copernicus', 'lorentz', 'faraday', 'heisenberg',
        ))))
        vboxg1 = QVBoxLayout(self.group1)
        for each_widget in (
            QLabel(' Target directory dath: '), self.outdir, self.btn1,
            QLabel(' Extra search path: '), self.srcdir, self.btn2,
            QLabel(' CLI Prompt prefix (Optional): '), self.prefx, self.btn3):
            vboxg1.addWidget(each_widget)

        self.group2 = QGroupBox()
        self.group2.setTitle(' Options ')
        self.group2.setCheckable(True)
        self.group2.setGraphicsEffect(QGraphicsBlurEffect(self))
        self.group2.graphicsEffect().setEnabled(False)
        self.group2.toggled.connect(self.toggle_options_group)
        self.qckb1, self.combo1 = QCheckBox(' Use Debug'), QDoubleSpinBox()
        self.qckb2 = QCheckBox(' Clear out the target directory')
        self.qckb3 = QCheckBox(' System-wide Python Packages')
        self.qckb4 = QCheckBox(' Unzip Setuptool or Distribute to virtualenv')
        self.qckb5 = QCheckBox(' Force the use of SetupTools')
        self.qckb6 = QCheckBox(' Never download packages')
        self.qckb7 = QCheckBox(' Delete .PYC files from virtualenv')
        self.qckb8 = QCheckBox(' Open target directory later')
        self.qckb9 = QCheckBox(' Save a LOG file to target later')
        self.qckb10 = QCheckBox(' No install PIP in the new virtualenv')
        self.qckb11 = QCheckBox('Save Bash script to reproduce virtenv later')
        self.chrt = QCheckBox('LOW CPU priority for Backend Process')
        self.combo1.setValue(2.7)
        self.combo1.setMaximum(3.4)
        self.combo1.setMinimum(2.4)
        self.combo1.setDecimals(1)
        self.combo1.setSingleStep(0.1)
        try:
            self.vinfo = QLabel('<small><b> Virtualenv Version: </b>' +
                            getoutput('virtualenv --version', shell=1).strip())
        except:
            self.vinfo = QLabel('Warning: Failed to query Virtualenv Backend!')
        [a.setChecked(True) for a in (self.qckb1, self.qckb4, self.qckb7,
                                self.chrt, self.qckb8, self.qckb9, self.qckb11)]
        vboxg2 = QVBoxLayout(self.group2)
        for each_widget in (self.qckb1, self.qckb2, self.qckb3, self.qckb4,
            self.qckb5, self.qckb6, self.qckb7, self.qckb8, self.qckb9,
            self.qckb10, self.qckb11, QLabel(' Python interpreter version: '),
            self.combo1, QLabel(' Backend CPU priority: '), self.chrt):
            vboxg2.addWidget(each_widget)

        self.button = QPushButton(' Make Virtualenv ')
        self.button.setCursor(QCursor(Qt.PointingHandCursor))
        self.button.setMinimumSize(75, 50)
        self.button.clicked.connect(self.run)
        glow = QGraphicsDropShadowEffect(self)
        glow.setOffset(0)
        glow.setBlurRadius(99)
        glow.setColor(QColor(99, 255, 255))
        self.button.setGraphicsEffect(glow)
        self.output = QTextEdit(''' " Let the future tell the truth,
        and evaluate each one according to his work and accomplishments.
        The present is theirs; the future, for which I really worked, is mine. "
        -Nikola Tesla. ''')

        class TransientWidget(QWidget):
            ' persistant widget thingy '
            def __init__(self, widget_list):
                ' init sub class '
                super(TransientWidget, self).__init__()
                vbox = QVBoxLayout(self)
                for each_widget in widget_list:
                    vbox.addWidget(each_widget)

        tw = TransientWidget((self.group1, self.group2, QLabel('Backend Logs'),
                              self.output, self.vinfo, self.button))
        self.scrollable, self.dock = QScrollArea(), QDockWidget()
        self.scrollable.setWidgetResizable(True)
        self.scrollable.setWidget(tw)
        self.dock.setWindowTitle(__doc__)
        self.dock.setStyleSheet('QDockWidget::title{text-align: center;}')
        self.dock.setWidget(self.scrollable)
        ExplorerContainer().addTab(self.dock, "Virtualenv")
        QPushButton(QIcon.fromTheme("help-about"), 'About', self.dock
            ).clicked.connect(lambda:
            QMessageBox.information(self.dock, __doc__, HELPMSG))

    def readOutput(self):
        """Read and append sphinx-build output to the logBrowser"""
        self.output.append(str(self.process.readAllStandardOutput()).strip())

    def readErrors(self):
        """Read and append sphinx-build errors to the logBrowser"""
        self.output.append(self.formatErrorMsg(str(
                                        self.process.readAllStandardError())))

    def formatErrorMsg(self, msg):
        """Format error messages in red color"""
        return self.formatMsg(msg, 'red')

    def formatInfoMsg(self, msg):
        """Format informative messages in blue color"""
        return self.formatMsg(msg, 'green')

    def formatMsg(self, msg, color):
        """Format message with the given color"""
        return '<font color="{}">{}</font>'.format(color, msg)

    def make_virtualenv(self):
        ' make virtualenv from contextual sub menu '
        self.outdir.setText(self.ex_locator.get_current_project_item().path)
        self.run()

    def run(self):
        ' run the actions '
        self.output.clear()
        self.output.append(self.formatInfoMsg(
                            'INFO: OK: Starting at {}'.format(datetime.now())))
        self.button.setDisabled(True)
        # Parse Values
        arg0 = '' if self.qckb10.isChecked() is False else '--no-pip '
        arg1 = '--quiet ' if self.qckb1.isChecked() is False else '--verbose '
        arg2 = '' if self.qckb2.isChecked() is False else '--clear '
        arg3 = '' if self.qckb3.isChecked() is False else '--system-site-packages '
        arg4 = '' if self.qckb4.isChecked() is False else '--unzip-setuptools '
        arg5 = '' if self.qckb5.isChecked() is False else '--setuptools '
        arg6 = '' if self.qckb6.isChecked() is False else '--never-download '
        # if the target is empty return
        if not len(str(self.outdir.text()).strip()):
            self.output.append(self.formatErrorMsg('ERROR: FAIL: Target empty'))
            self.button.setEnabled(True)
            return
        else:
            self.output.append(self.formatInfoMsg(
            'INFO: OK: Output Directory is {}'.format(self.outdir.text())))
        # prefix
        prf = str(self.prefx.text()).upper().strip().replace(' ', '')
        arg10 = '' if prf is '' else '--prompt="{}_" '.format(prf)
        self.output.append(self.formatInfoMsg('INFO: Prefix: {}'.format(arg10)))
        # extra search dir
        src = str(self.srcdir.text()).strip()
        arg11 = '' if src is '' else '--extra-search-dir="{}" '.format(src)
        self.output.append(self.formatInfoMsg(' INFO: Extra: {}'.format(arg11)))
        self.output.append(self.formatInfoMsg(
            ' INFO: OK: Write Logs ?: {} '.format(self.qckb9.isChecked())))
        self.output.append(self.formatInfoMsg(
            ' INFO: OK: Open Directory ?: {} '.format(self.qckb8.isChecked())))
        # run the subprocesses
        cmd = '{}virtualenv {}{}{}{}{}{}{}-p python{} {}{} {}'.format(
            'chrt --verbose -i 0 ' if self.chrt.isChecked() is True else '',
            arg0, arg1, arg2, arg3, arg4, arg5, arg6,
            self.combo1.value(), arg11, arg10, str(self.outdir.text()).strip())
        self.output.append(self.formatInfoMsg('INFO:OK:Command:{}'.format(cmd)))
        self.process.start(cmd)
        if not self.process.waitForStarted():
            self.output.append(self.formatErrorMsg(' ERROR: FAIL: Meh. '))
            self.output.append(self.formatErrorMsg(
                'ERROR: FAIL: Failed with Arguments: {} '.format(cmd)))
            self.button.setEnabled(True)
            return
         # write a .sh bash script file on target
        if self.qckb11.isChecked() is True:
            sh_file = 'create_virtualenv.sh'
            with open(path.join(str(self.outdir.text()), sh_file), 'w') as _sh:
                self.output.append(self.formatInfoMsg('''INFO: OK: Writing Bash:
                    {}'''.format(path.join(str(self.outdir.text()), sh_file))))
                _sh.write('#!/usr/bin/env bash' + linesep + cmd)
                _sh.close()
            self.output.append(self.formatInfoMsg('INFO: OK: Bash chmod: 775'))
            try:
                chmod(path.join(str(self.outdir.text()), sh_file), 0775)  # Py2
            except:
                chmod(path.join(str(self.outdir.text()), sh_file), 0o775)  # Py3
        self.readOutput()
        self.readErrors()
        self.button.setEnabled(True)

    def _process_finished(self):
        """ finished sucessfully """
        self.output.append(self.formatInfoMsg(
                            'INFO: OK: Finished at {}'.format(datetime.now())))
        # remove all *.PYC bytecode
        if self.qckb7.isChecked() is True:
            self.output.append(self.formatInfoMsg(' INFO: OK: Removing *.PYC '))
            self.output.append(self.formatInfoMsg(' INFO: This takes a moment'))
            [remove(path.join(root, f)) for root, f in list(itertools.chain(*
            [list(itertools.product([root], files))
            for root, dirs, files in walk(str(self.outdir.text()).strip())]))
            if f.endswith(('.pyc', '.PYC')) and not f.startswith('.')]
        # write a .log file on target
        if self.qckb9.isChecked() is True:
            log_file = 'virtualenv_gui.log'
            with open(path.join(str(self.outdir.text()), log_file), 'w') as log:
                self.output.append(self.formatInfoMsg('''INFO: OK: Writing Logs:
                    {}'''.format(path.join(str(self.outdir.text()), log_file))))
                log.write(self.output.toPlainText())
                log.close()
        # open target dir
        if self.qckb8.isChecked() is True:
            try:
                startfile(str(self.outdir.text()))
            except:
                Popen(["xdg-open", str(self.outdir.text())])
        self.output.selectAll()
        self.output.setFocus()

    def toggle_options_group(self):
        ' toggle on off the options group '
        if self.group2.isChecked() is True:
            [a.setChecked(True) for a in (self.qckb1, self.qckb4, self.qckb7,
                                self.chrt, self.qckb8, self.qckb9, self.qckb11)]
            self.combo1.setValue(2.7)
            self.group2.graphicsEffect().setEnabled(False)
        else:
            [a.setChecked(False) for a in (self.qckb1, self.qckb4, self.qckb7,
                                self.chrt, self.qckb8, self.qckb9, self.qckb11)]
            self.group2.graphicsEffect().setEnabled(True)

    def finish(self):
        ' clear when finish '
        self.process.kill()
예제 #3
0
파일: main.py 프로젝트: Zekom/webutil
class Main(plugin.Plugin):
    " Main Class "
    def initialize(self, *args, **kwargs):
        " Init Main Class "
        ec = ExplorerContainer()
        super(Main, self).initialize(*args, **kwargs)

        self.editor_s = self.locator.get_service('editor')
        # directory auto completer
        self.completer = QCompleter(self)
        self.dirs = QDirModel(self)
        self.dirs.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot)
        self.completer.setModel(self.dirs)
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setCompletionMode(QCompleter.PopupCompletion)

        self.group0 = QGroupBox()
        self.group0.setTitle(' Source ')
        self.source = QComboBox()
        self.source.addItems(['Clipboard', 'Local File', 'Remote URL', 'Ninja'])
        self.source.currentIndexChanged.connect(self.on_source_changed)
        self.infile = QLineEdit(path.expanduser("~"))
        self.infile.setPlaceholderText(' /full/path/to/file.html ')
        self.infile.setCompleter(self.completer)
        self.open = QPushButton(QIcon.fromTheme("folder-open"), 'Open')
        self.open.setCursor(QCursor(Qt.PointingHandCursor))
        self.open.clicked.connect(lambda: self.infile.setText(str(
            QFileDialog.getOpenFileName(self.dock, "Open a File to read from",
            path.expanduser("~"), ';;'.join(['{}(*.{})'.format(e.upper(), e)
            for e in ['css', 'html', 'js', 'txt', '*']])))))
        self.inurl = QLineEdit('http://www.')
        self.inurl.setPlaceholderText('http://www.full/url/to/remote/file.html')
        self.output = QPlainTextEdit(SAMPLE_TEXT)
        vboxg0 = QVBoxLayout(self.group0)
        for each_widget in (self.source, self.infile, self.open, self.inurl,
            self.output, ):
            vboxg0.addWidget(each_widget)
        [a.hide() for a in iter((self.infile, self.open, self.inurl))]

        self.group1 = QGroupBox()
        self.group1.setTitle(' CSS3 ')
        self.group1.setCheckable(True)
        self.group1.setGraphicsEffect(QGraphicsBlurEffect(self))
        self.group1.graphicsEffect().setEnabled(False)
        self.group1.toggled.connect(self.toggle_css_group)
        self.ckcss1 = QCheckBox('Remove unnecessary Comments')
        self.ckcss2 = QCheckBox('Remove unnecessary Whitespace characters')
        self.ckcss3 = QCheckBox('Remove unnecessary Semicolons')
        self.ckcss4 = QCheckBox('Remove unnecessary Empty rules')
        self.ckcss5 = QCheckBox('Condense and Convert Colors from RGB to HEX')
        self.ckcss6 = QCheckBox('Condense all Zero units')
        self.ckcss7 = QCheckBox('Condense Multidimensional Zero units')
        self.ckcss8 = QCheckBox('Condense Floating point numbers')
        self.ckcss9 = QCheckBox('Condense HEX Colors')
        self.ckcss10 = QCheckBox('Condense multiple adjacent Whitespace chars')
        self.ckcss11 = QCheckBox('Condense multiple adjacent semicolon chars')
        self.ckcss12 = QCheckBox('Wrap the lines of the to 80 character length')
        self.ckcss13 = QCheckBox('Condense Font Weight values')
        self.ckcss14 = QCheckBox('Condense the 17 Standard Named Colors values')
        self.ckcss15 = QCheckBox('Condense the 124 Extra Named Colors values')
        self.ckcss16 = QCheckBox('Condense all Percentages values when posible')
        self.ckcss17 = QCheckBox('Condense all Pixels values when posible')
        self.ckcss18 = QCheckBox('Remove unnecessary quotes from url()')
        self.ckcss19 = QCheckBox('Add standard Encoding Declaration if missing')
        vboxg1 = QVBoxLayout(self.group1)
        for each_widget in (self.ckcss1, self.ckcss2, self.ckcss3, self.ckcss4,
            self.ckcss5, self.ckcss6, self.ckcss7, self.ckcss8, self.ckcss9,
            self.ckcss10, self.ckcss11, self.ckcss12, self.ckcss13,
            self.ckcss14, self.ckcss15, self.ckcss16, self.ckcss17,
            self.ckcss18, self.ckcss19):
            vboxg1.addWidget(each_widget)
            each_widget.setToolTip(each_widget.text())

        self.group2 = QGroupBox()
        self.group2.setTitle(' HTML5 ')
        self.group2.setCheckable(True)
        self.group2.setGraphicsEffect(QGraphicsBlurEffect(self))
        self.group2.graphicsEffect().setEnabled(False)
        self.group2.toggled.connect(self.toggle_html_group)
        self.ckhtml0 = QCheckBox('Condense Style and Script HTML Tags')
        self.ckhtml1 = QCheckBox('Condense DOCTYPE to new HTML5 Tags')
        self.ckhtml2 = QCheckBox('Condense Href and Src to protocol agnostic')
        self.ckhtml4 = QCheckBox('Remove unnecessary Tags but keep HTML valid')
        self.help1 = QLabel('''<a href=
            "https://developers.google.com/speed/articles/optimizing-html">
            <small><center>Help about Unneeded Unnecessary HTML tags ?</a>''')
        self.help1.setTextInteractionFlags(Qt.LinksAccessibleByMouse)
        self.help1.setOpenExternalLinks(True)
        vboxg2 = QVBoxLayout(self.group2)
        for each_widget in (self.ckhtml0, self.ckhtml1, self.ckhtml2,
            self.ckhtml4, self.help1, ):
            vboxg2.addWidget(each_widget)
            each_widget.setToolTip(each_widget.text())

        self.group3 = QGroupBox()
        self.group3.setTitle(' Javascript ')
        self.ckjs0 = QCheckBox('Condense and Compress Javascript')
        self.ckjs1 = QCheckBox('Condense $(document).ready(function(){ });')
        vboxg2 = QVBoxLayout(self.group3)
        for each_widget in (self.ckjs0, self.ckjs1):
            vboxg2.addWidget(each_widget)
            each_widget.setToolTip(each_widget.text())

        self.group4 = QGroupBox()
        self.group4.setTitle(' General ')
        self.chckbx1 = QCheckBox('Lower case ALL the text')
        self.chckbx2 = QCheckBox('Remove Spaces, Tabs, New Lines, Empty Lines')
        self.befor, self.after = QProgressBar(), QProgressBar()
        self.befor.setFormat("%v Chars")
        self.after.setFormat("%v Chars")
        vboxg4 = QVBoxLayout(self.group4)
        for each_widget in (self.chckbx1, self.chckbx2,
            QLabel('<b>Before:'), self.befor, QLabel('<b>After:'), self.after):
            vboxg4.addWidget(each_widget)
            each_widget.setToolTip(each_widget.text())

        [a.setChecked(True) for a in iter((self.ckcss1, self.ckcss2,
            self.ckcss3, self.ckcss4, self.ckcss5, self.ckcss6, self.ckcss7,
            self.ckcss8, self.ckcss9, self.ckcss10, self.ckcss11, self.ckcss12,
            self.ckcss13, self.ckcss14, self.ckcss15, self.ckcss16,
            self.ckcss17, self.ckcss18, self.ckcss19, self.ckjs1, self.ckhtml0,
            self.ckhtml1, self.ckhtml2, self.ckhtml4, self.chckbx1,
            self.chckbx2))]

        self.button = QPushButton(QIcon.fromTheme("face-cool"), 'Process Text')
        self.button.setCursor(QCursor(Qt.PointingHandCursor))
        self.button.setMinimumSize(100, 50)
        self.button.clicked.connect(self.run)

        def must_glow(widget_list):
            ' apply an glow effect to the widget '
            for glow, each_widget in enumerate(widget_list):
                try:
                    if each_widget.graphicsEffect() is None:
                        glow = QGraphicsDropShadowEffect(self)
                        glow.setOffset(0)
                        glow.setBlurRadius(99)
                        glow.setColor(QColor(99, 255, 255))
                        each_widget.setGraphicsEffect(glow)
                        glow.setEnabled(True)
                except:
                    pass

        must_glow((self.button, ))

        class TransientWidget(QWidget):
            ' persistant widget thingy '
            def __init__(self, widget_list):
                ' init sub class '
                super(TransientWidget, self).__init__()
                vbox = QVBoxLayout(self)
                for each_widget in widget_list:
                    vbox.addWidget(each_widget)

        tw = TransientWidget((QLabel('<b>HTML5/CSS3/JS Optimizer Compressor'),
            self.group0, self.group1, self.group2, self.group3, self.group4,
            self.button, ))
        self.scrollable = QScrollArea()
        self.scrollable.setWidgetResizable(True)
        self.scrollable.setWidget(tw)
        self.dock = QDockWidget()
        self.dock.setWindowTitle(__doc__)
        self.dock.setStyleSheet('QDockWidget::title{text-align: center;}')
        self.dock.setMinimumWidth(350)
        self.dock.setWidget(self.scrollable)
        ec.addTab(self.dock, "Web")
        QPushButton(QIcon.fromTheme("help-about"), 'About', self.dock
          ).clicked.connect(lambda: QMessageBox.information(self.dock, __doc__,
            HELPMSG))

    def run(self):
        ' run the string replacing '
        if self.source.currentText() == 'Local File':
            with open(path.abspath(str(self.infile.text()).strip()), 'r') as f:
                txt = f.read()
        elif self.source.currentText() == 'Remote URL':
            txt = urlopen(str(self.inurl.text()).strip()).read()
        elif  self.source.currentText() == 'Clipboard':
            txt = str(self.output.toPlainText()) if str(self.output.toPlainText()) is not '' else str(QApplication.clipboard().text())
        else:
            txt = self.editor_s.get_text()
        self.output.clear()
        self.befor.setMaximum(len(txt) + 10)
        self.after.setMaximum(len(txt) + 10)
        self.befor.setValue(len(txt))
        txt = txt.lower() if self.chckbx1.isChecked() is True else txt
        txt = condense_style(txt) if self.ckhtml0.isChecked() is True else txt
        txt = condense_script(txt) if self.ckhtml0.isChecked() is True else txt
        txt = condense_doctype(txt) if self.ckhtml1.isChecked() is True else txt
        txt = condense_href_src(txt) if self.ckhtml2 is True else txt
        txt = clean_unneeded_tags(txt) if self.ckhtml4.isChecked() is True else txt
        txt = condense_doc_ready(txt) if self.ckjs1.isChecked() is True else txt
        txt = jsmin(txt) if self.ckjs0.isChecked() is True else txt
        txt = remove_comments(txt) if self.ckcss1.isChecked() is True else txt
        txt = condense_whitespace(txt) if self.ckcss10.isChecked() is True else txt
        txt = remove_empty_rules(txt) if self.ckcss4.isChecked() is True else txt
        txt = remove_unnecessary_whitespace(txt) if self.ckcss2.isChecked() is True else txt
        txt = remove_unnecessary_semicolons(txt) if self.ckcss3.isChecked() is True else txt
        txt = condense_zero_units(txt) if self.ckcss6.isChecked() is True else txt
        txt = condense_multidimensional_zeros(txt) if self.ckcss7.isChecked() is True else txt
        txt = condense_floating_points(txt) if self.ckcss8.isChecked() is True else txt
        txt = normalize_rgb_colors_to_hex(txt) if self.ckcss5.isChecked() is True else txt
        txt = condense_hex_colors(txt) if self.ckcss9.isChecked() is True else txt
        txt = wrap_css_lines(txt, 80) if self.ckcss12.isChecked() is True else txt
        txt = condense_semicolons(txt) if self.ckcss11.isChecked() is True else txt
        txt = condense_font_weight(txt) if self.ckcss13.isChecked() is True else txt
        txt = condense_std_named_colors(txt) if self.ckcss14.isChecked() is True else txt
        # txt = condense_xtra_named_colors(txt) if self.ckcss14.isChecked() is True else txt  # FIXME
        txt = condense_percentage_values(txt) if self.ckcss16.isChecked() is True else txt
        txt = condense_pixel_values(txt) if self.ckcss17.isChecked() is True else txt
        txt = remove_url_quotes(txt) if self.ckcss18.isChecked() is True else txt
        txt = add_encoding(txt) if self.ckcss19.isChecked() is True else txt
        txt = " ".join(txt.strip().split()) if self.chckbx2.isChecked() is True else txt
        self.after.setValue(len(txt))
        self.output.setPlainText(txt)
        self.output.show()
        self.output.setFocus()
        self.output.selectAll()

    def on_source_changed(self):
        ' do something when the desired source has changed '
        if self.source.currentText() == 'Local File':
            self.open.show()
            self.infile.show()
            self.inurl.hide()
            self.output.hide()
        elif  self.source.currentText() == 'Remote URL':
            self.inurl.show()
            self.open.hide()
            self.infile.hide()
            self.output.hide()
        elif  self.source.currentText() == 'Clipboard':
            self.output.show()
            self.open.hide()
            self.infile.hide()
            self.inurl.hide()
            self.output.setText(QApplication.clipboard().text())
        else:
            self.output.show()
            self.open.hide()
            self.infile.hide()
            self.inurl.hide()
            self.output.setText(self.editor_s.get_text())

    def toggle_css_group(self):
        ' toggle on or off the css checkboxes '
        if self.group1.isChecked() is True:
            [a.setChecked(True) for a in iter((self.ckcss1, self.ckcss2,
            self.ckcss3, self.ckcss4, self.ckcss5, self.ckcss6, self.ckcss7,
            self.ckcss8, self.ckcss9, self.ckcss10, self.ckcss11, self.ckcss12,
            self.ckcss13, self.ckcss14, self.ckcss15, self.ckcss16,
            self.ckcss17, self.ckcss18, self.ckcss19))]
            self.group1.graphicsEffect().setEnabled(False)
        else:
            [a.setChecked(False) for a in iter((self.ckcss1, self.ckcss2,
            self.ckcss3, self.ckcss4, self.ckcss5, self.ckcss6, self.ckcss7,
            self.ckcss8, self.ckcss9, self.ckcss10, self.ckcss11, self.ckcss12,
            self.ckcss13, self.ckcss14, self.ckcss15, self.ckcss16,
            self.ckcss17, self.ckcss18, self.ckcss19))]
            self.group1.graphicsEffect().setEnabled(True)

    def toggle_html_group(self):
        ' toggle on or off the css checkboxes '
        if self.group2.isChecked() is True:
            [a.setChecked(True) for a in iter((self.ckhtml0, self.ckhtml1,
                                               self.ckhtml2, self.ckhtml4))]
            self.group2.graphicsEffect().setEnabled(False)
        else:
            [a.setChecked(False) for a in iter((self.ckhtml0, self.ckhtml1,
                                                self.ckhtml2, self.ckhtml4))]
            self.group2.graphicsEffect().setEnabled(True)
예제 #4
0
class Main(plugin.Plugin):
    " Main Class "
    def initialize(self, *args, **kwargs):
        " Init Main Class "
        super(Main, self).initialize(*args, **kwargs)
        self.completer, self.dirs = QCompleter(self), QDirModel(self)
        self.dirs.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot)
        self.completer.setModel(self.dirs)
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setCompletionMode(QCompleter.PopupCompletion)

        self.desktop, self.project, menu = '', '', QMenu('Vagrant')
        menu.addAction('UP', lambda: self.vagrant_c('up'))
        menu.addAction('HALT', lambda: self.vagrant_c('halt'))
        menu.addAction('RELOAD', lambda: self.vagrant_c('reload'))
        menu.addAction('STATUS', lambda: self.vagrant_c('status'))
        menu.addAction('SUSPEND', lambda: self.vagrant_c('suspend'))
        menu.addAction('RESUME', lambda: self.vagrant_c('resume'))
        menu.addAction('PROVISION', lambda: self.vagrant_c('provision'))
        menu.addAction('PACKAGE', lambda: self.vagrant_c('package'))
        menu.addAction('INIT', lambda: self.vagrant_c('init'))
        menu.addSeparator()
        menu.addAction('DESTROY (!!!)', lambda: self.vagrant_c('destroy'))
        self.locator.get_service('explorer').add_project_menu(menu, lang='all')

        self.process = QProcess()
        self.process.readyReadStandardOutput.connect(self.readOutput)
        self.process.readyReadStandardError.connect(self.readErrors)
        self.process.finished.connect(self._process_finished)
        self.process.error.connect(self._process_finished)

        # Proxy support, by reading http_proxy os env variable
        proxy_url = QUrl(environ.get('http_proxy', ''))
        QNetworkProxy.setApplicationProxy(QNetworkProxy(QNetworkProxy.HttpProxy
            if str(proxy_url.scheme()).startswith('http')
            else QNetworkProxy.Socks5Proxy, proxy_url.host(), proxy_url.port(),
                 proxy_url.userName(), proxy_url.password())) \
            if 'http_proxy' in environ else None

        self.mainwidget = QTabWidget()
        self.mainwidget.tabCloseRequested.connect(lambda:
            self.mainwidget.setTabPosition(1)
            if self.mainwidget.tabPosition() == 0
            else self.mainwidget.setTabPosition(0))
        self.mainwidget.setStyleSheet('QTabBar{font-weight:bold;}')
        self.mainwidget.setMovable(True)
        self.mainwidget.setTabsClosable(True)

        self.dock, self.scrollable = QDockWidget(), QScrollArea()
        self.scrollable.setWidgetResizable(True)
        self.scrollable.setWidget(self.mainwidget)
        self.dock.setWindowTitle(__doc__)
        self.dock.setStyleSheet('QDockWidget::title{text-align: center;}')
        self.dock.setWidget(self.scrollable)

        self.locator.get_service('misc').add_widget(self.dock,
                                 QIcon.fromTheme("virtualbox"), __doc__)

        self.tab1, self.tab2, self.tab3 = QGroupBox(), QGroupBox(), QGroupBox()
        self.tab4, self.tab5, self.tab6 = QGroupBox(), QGroupBox(), QGroupBox()
        for a, b in ((self.tab1, 'Basics'), (self.tab2, 'General Options'),
            (self.tab3, 'VM Package Manager'), (self.tab4, 'VM Provisioning'),
            (self.tab5, 'VM Desktop GUI'), (self.tab6, 'Run')):
            a.setTitle(b)
            a.setToolTip(b)
            self.mainwidget.addTab(a, QIcon.fromTheme("virtualbox"), b)

        QPushButton(QIcon.fromTheme("help-about"), 'About', self.dock
        ).clicked.connect(lambda: QMessageBox.information(self.dock, __doc__,
        HELPMSG))

        self.vmname = QLineEdit(self.get_name())
        self.vmname.setPlaceholderText('type_your_VM_name_here_without_spaces')
        self.vmname.setToolTip('Type VM name, no spaces or special characters')
        self.target = QLabel('<b>Vagrant Target Folder: ' +
                             path.join(BASE, self.vmname.text()))
        self.vmname.textChanged.connect(lambda: self.target.setText(
            '<b>Vagrant Target Folder: ' + path.join(BASE, self.vmname.text())))
        self.btn1 = QPushButton(QIcon.fromTheme("face-smile-big"), 'Suggestion')
        self.btn1.setToolTip('Suggest me a Random VM name !')
        self.btn1.clicked.connect(lambda: self.vmname.setText(self.get_name()))
        self.vmcode, self.vmarch = QComboBox(), QComboBox()
        self.vmcode.addItems(['saucy', 'raring', 'quantal', 'precise'])
        self.vmarch.addItems(['x86_64 (amd64) 64-Bits', 'x86 (i386) 32-Bits'])
        vboxg1 = QVBoxLayout(self.tab1)
        for each_widget in (QLabel('<b>Name for VM'), self.vmname, self.btn1,
            QLabel('<b>Choose Ubuntu Codename for the VM:</b>'), self.vmcode,
            QLabel('<b>Choose Architecture for VM:'), self.vmarch, self.target):
            vboxg1.addWidget(each_widget)

        self.chrt = QCheckBox('LOW CPU priority for Backend Process')
        self.chttps = QComboBox()
        self.chttps.addItems(['https', 'http'])
        try:
            self.vinfo1 = QLabel('''<b> Vagrant Backend Version: </b> {},
                <b> VirtualBox Backend Version: </b> {}. '''.format(
                getoutput('vagrant --version', shell=1).strip(),
                getoutput('vboxmanage --version', shell=1).strip()))
        except:
            self.vinfo1 = QLabel('<b>Warning: Failed to query Vagrant Backend!')
        self.qckb1 = QCheckBox(' Open target directory later')
        self.qckb1.setToolTip('Open the target directory when finished')
        self.qckb2 = QCheckBox(' Save a LOG file to target later')
        self.qckb2.setToolTip('Save a read-only .LOG file to target')
        self.qckb3 = QCheckBox(' NO run Headless Mode, use a Window')
        self.qckb3.setToolTip('Show the VM on a Window GUI instead of Headless')
        self.cpu, self.ram = QSpinBox(), QSpinBox()
        self.cpu.setRange(25, 99)
        self.cpu.setValue(99)
        self.ram.setRange(512, 4096)
        self.ram.setValue(1024)
        vboxg2 = QVBoxLayout(self.tab2)
        for each_widget in (self.qckb1, self.qckb2, self.qckb3, self.chrt,
            QLabel('<b>Max CPU Limit for VM:</b>'), self.cpu,
            QLabel('<b>Max RAM Limit for VM:</b>'), self.ram,
            QLabel('<b>Download Protocol Type:</b>'), self.chttps, self.vinfo1):
            vboxg2.addWidget(each_widget)

        self.qckb10 = QCheckBox('Run apt-get update on the created VM')
        self.qckb11 = QCheckBox('Run apt-get dist-upgrade on the created VM')
        self.qckb12 = QCheckBox('Run apt-get check on the created VM')
        self.qckb12 = QCheckBox('Run apt-get clean on the created VM')
        self.qckb13 = QCheckBox('Run apt-get autoremove on the created VM')
        self.qckb14 = QCheckBox('Try to Fix Broken packages if any on the VM')
        self.aptproxy, self.portredirect = QLineEdit(), QLineEdit('8000, 9000')
        self.aptproxy.setPlaceholderText(' user:password@proxyaddress:port ')
        vboxg3 = QVBoxLayout(self.tab3)
        for each_widget in (self.qckb10, self.qckb11, self.qckb12, self.qckb13,
            self.qckb14,
            QLabel('<b>Network Proxy for apt-get on the VM'), self.aptproxy,
            QLabel('<b>Network Port Redirects for the VM'), self.portredirect):
            vboxg3.addWidget(each_widget)

        self.aptpkg = QTextEdit('build-essential git python-pip vim mc wget')
        self.aptppa, self.pippkg = QLineEdit(), QTextEdit('virtualenv yolk')
        self.aptppa.setPlaceholderText(' ppa:ninja-ide-developers/daily ')
        self.requirements = QLineEdit()
        self.requirements.setPlaceholderText(' /full/path/to/requirements.txt ')
        self.requirements.setCompleter(self.completer)
        vboxg4 = QVBoxLayout(self.tab4)
        for each_widget in (QLabel('<b>Custom APT Ubuntu package'), self.aptpkg,
            QLabel('<b>Custom APT Ubuntu PPA:</b>      '), self.aptppa,
            QLabel('<b>Custom PIP Python packages:</b> '), self.pippkg,
            QLabel('<b>Custom PIP Python requirements: '), self.requirements):
            vboxg4.addWidget(each_widget)

        self.buttonGroup = QButtonGroup()
        self.buttonGroup.buttonClicked[QAbstractButton].connect(self.get_de_pkg)
        vboxg5 = QVBoxLayout(self.tab5)
        for i, d in enumerate(('Ubuntu Unity', 'KDE Plasma', 'LXDE', 'XFCE')):
            button = QPushButton(d)
            button.setCheckable(True)
            button.setMinimumSize(75, 50)
            button.setToolTip(d)
            vboxg5.addWidget(button)
            self.buttonGroup.addButton(button)

        self.output = QTextEdit('''
        We have persistent objects, they are called files.  -Ken Thompson. ''')
        self.runbtn = QPushButton(QIcon.fromTheme("media-playback-start"),
            'Start Vagrant Instrumentation Now !')
        self.runbtn.setMinimumSize(75, 50)
        self.runbtn.clicked.connect(self.build)
        glow = QGraphicsDropShadowEffect(self)
        glow.setOffset(0)
        glow.setBlurRadius(99)
        glow.setColor(QColor(99, 255, 255))
        self.runbtn.setGraphicsEffect(glow)
        self.stopbt = QPushButton(QIcon.fromTheme("media-playback-stop"),
            'Stop Vagrant')
        self.stopbt.clicked.connect(lambda: self.process.stop())
        self.killbt = QPushButton(QIcon.fromTheme("application-exit"),
            'Force Kill Vagrant')
        self.killbt.clicked.connect(lambda: self.process.kill())
        vboxg6 = QVBoxLayout(self.tab6)
        for each_widget in (QLabel('<b>Multiprocess Output Logs'), self.output,
            self.runbtn, self.stopbt, self.killbt):
            vboxg6.addWidget(each_widget)

        [a.setChecked(True) for a in (self.qckb1, self.qckb2, self.qckb3,
            self.qckb10, self.qckb11, self.qckb12, self.qckb13, self.qckb14,
            self.chrt)]
        self.mainwidget.setCurrentIndex(5)

    def get_de_pkg(self, button):
        ' get package from desktop name '
        if button.text() in 'Ubuntu Unity':
            self.desktop = 'ubuntu-desktop'
        elif button.text() in 'KDE Plasma':
            self.desktop = 'kubuntu-desktop'
        elif button.text() in 'LXDE':
            self.desktop = 'lubuntu-desktop'
        else:
            self.desktop = 'xubuntu-desktop'
        return self.desktop

    def get_name(self):
        ' return a random name of stars, planets and moons of solar system '
        return choice((getuser(), 'sun', 'mercury', 'venus', 'earth', 'mars',
            'neptun', 'ceres', 'pluto', 'haumea', 'makemake', 'eris', 'moon',
            'saturn', 'europa', 'ganymede', 'callisto', 'mimas', 'enceladus',
            'tethys', 'dione', 'rhea', 'titan', 'iapetus', 'miranda', 'ariel',
            'umbriel', 'titania', 'oberon', 'triton', 'charon', 'orcus', 'io',
            'ixion', 'varuna', 'quaoar', 'sedna', 'methone', 'jupiter', ))

    def readOutput(self):
        """Read and append output to the logBrowser"""
        self.output.append(str(self.process.readAllStandardOutput()))

    def readErrors(self):
        """Read and append errors to the logBrowser"""
        self.output.append(self.formatErrorMsg(str(
                                        self.process.readAllStandardError())))

    def formatErrorMsg(self, msg):
        """Format error messages in red color"""
        return self.formatMsg(msg, 'red')

    def formatInfoMsg(self, msg):
        """Format informative messages in blue color"""
        return self.formatMsg(msg, 'green')

    def formatMsg(self, msg, color):
        """Format message with the given color"""
        return '<font color="{}">{}</font>'.format(color, msg)

    def build(self):
        """Main function calling vagrant to generate the vm"""
        self.output.setText('')
        self.output.append(self.formatInfoMsg('INFO:{}'.format(datetime.now())))
        self.runbtn.setDisabled(True)
        base = path.join(BASE, self.vmname.text())
        try:
            self.output.append(self.formatInfoMsg('INFO: Dir: {}'.format(base)))
            makedirs(base)
        except:
            self.output.append(self.formatErrorMsg('ERROR:Target Folder Exist'))
        self.output.append(self.formatInfoMsg('INFO: Changed {}'.format(base)))
        chdir(base)
        try:
            self.output.append(self.formatInfoMsg('INFO:Removing Vagrant file'))
            remove(path.join(base, 'Vagrantfile'))
        except:
            self.output.append(self.formatErrorMsg('ERROR:Remove Vagrant file'))
        self.output.append(self.formatInfoMsg(' INFO: OK: Runing Vagrant Init'))
        cmd1 = getoutput('chrt --verbose -i 0 vagrant init', shell=True)
        self.output.append(self.formatInfoMsg('INFO:OK:Completed Vagrant Init'))
        self.output.append(self.formatInfoMsg('INFO: Command: {}'.format(cmd1)))
        cfg = CONFIG.format(self.vmname.text(), self.vmname.text(),
            self.chttps.currentText(), self.vmcode.currentText(),
            self.vmcode.currentText(),
            'amd64' if self.vmarch.currentIndex() is 0 else 'i386',
            '\n'.join(([
            '    config.vm.network :forwarded_port, host: {}, guest: {}'.format(
                a, a) for a in str(self.portredirect.text()).split(',')])),
            VBOXGUI.format(self.ram.value(), self.cpu.value())
                if self.qckb3.isChecked() is True else '')
        self.output.append(self.formatInfoMsg('INFO:OK:Config: {}'.format(cfg)))
        with open(path.join(base, 'Vagrantfile'), 'w') as f:
            f.write(cfg)
            self.output.append(self.formatInfoMsg('INFO: Writing Vagrantfile'))
            f.close()
        proxy = APTGET_PROXY.format(self.aptproxy.text(), self.aptproxy.text(),
            self.aptproxy.text(), self.aptproxy.text(), self.aptproxy.text(),
            self.aptproxy.text())
        prv = '\n'.join(('#!/usr/bin/env bash', '# -*- coding: utf-8 -*-',
        linesep * 2, "PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] ' ; HISTSIZE=5000",
        '# Vagrant Bootstrap Provisioning generated by Vagrant Ninja!', linesep,
        proxy if len(self.aptproxy.text()) >= 5 else '',
        'add-apt-repository -s -y {}'.format(str(self.aptppa.text()).strip()),
        'apt-get -V -u -m -y update' if self.qckb10.isChecked() is True else '',
        'apt-get -y -m dist-upgrade' if self.qckb11.isChecked() is True else '',
        'apt-get -y -m autoremove' if self.qckb11.isChecked() is True else '',
        'apt-get -y clean' if self.qckb11.isChecked() is True else '',
        'dpkg --configure -a' if self.qckb11.isChecked() is True else '',
        'apt-get -y -f install' if self.qckb11.isChecked() is True else '',
        'apt-get -y check' if self.qckb11.isChecked() is True else '',
        'apt-get -y --force-yes install {}'.format(self.aptpkg.toPlainText()),
        'pip install --verbose {}'.format(self.pippkg.toPlainText()),
        'pip install --verbose -r {}'.format(self.requirements.text()),
        'apt-get -y --force-yes -m install {}'.format(self.desktop), linesep,
        'git config --global user.name "{}"'.format(getuser()),
        'git config --global color.branch auto',
        'git config --global color.diff auto',
        'git config --global color.interactive auto',
        'git config --global color.status auto',
        'git config --global credential.helper cache',
        'git config --global user.email "{}@gmail.com"'.format(getuser()),
        'git config --global push.default simple',
        'ufw status ; service ufw stop ; ufw disable ; swapoff --verbose --all',
        'export LANGUAGE=en_US.UTF-8', 'export LANG=en_US.UTF-8',
        'export LC_ALL=en_US.UTF-8', 'locale-gen en_US.UTF-8',
        'dpkg-reconfigure locales', ))
        self.output.append(self.formatInfoMsg('INFO:OK:Script: {}'.format(prv)))
        with open(path.join(base, 'bootstrap.sh'), 'w') as f:
            f.write(prv)
            self.output.append(self.formatInfoMsg('INFO: Writing bootstrap.sh'))
            f.close()
        try:
            chmod('bootstrap.sh', 0775)  # Py2
            self.output.append(self.formatInfoMsg('INFO: bootstrap.sh is 775'))
        except:
            chmod('bootstrap.sh', 0o775)  # Py3
            self.output.append(self.formatInfoMsg('INFO: bootstrap.sh is o775'))
        self.output.append(self.formatInfoMsg(''' INFO: OK:
        Vagrant Up needs time, depends on your Internet Connection Speed !'''))
        self.output.append(self.formatInfoMsg('INFO: OK: Running Vagrant Up !'))
        self.process.start('{}vagrant up'.format('chrt --verbose -i 0 '
            if self.chrt.isChecked() is True else ''))
        if not self.process.waitForStarted():
            self.output.append(self.formatErrorMsg('ERROR: FAIL: Vagrant Fail'))
            self.runbtn.setEnabled(True)
            return
        self.runbtn.setEnabled(True)
        chdir(path.expanduser("~"))

    def _process_finished(self):
        """finished sucessfully"""
        self.output.append(self.formatInfoMsg('INFO:{}'.format(datetime.now())))
        if self.qckb2.isChecked() is True:
            LOG_FILE = path.join(BASE, self.vmname.text(), 'vagrant_ninja.log')
            with open(LOG_FILE, 'w') as f:
                self.output.append(self.formatInfoMsg('INFO: OK: Writing .LOG'))
                f.write(self.output.toPlainText())
                f.close()
        if self.qckb1.isChecked() is True:
            self.output.append(self.formatInfoMsg('INFO:Opening Target Folder'))
            try:
                startfile(BASE)
            except:
                Popen(["xdg-open", BASE])
        chdir(path.expanduser("~"))

    def vagrant_c(self, option):
        ' run the choosed menu option, kind of quick-mode '
        self.output.setText('')
        self.output.append(self.formatInfoMsg('INFO:{}'.format(datetime.now())))
        self.runbtn.setDisabled(True)
        chdir(path.abspath(
          self.locator.get_service('explorer').get_current_project_item().path))
        self.process.start('chrt --verbose -i 0 vagrant {}'.format(option))
        if not self.process.waitForStarted():
            self.output.append(self.formatErrorMsg('ERROR: FAIL: Vagrant Fail'))
            self.runbtn.setEnabled(True)
            return
        self.runbtn.setEnabled(True)
        self.output.append(self.formatInfoMsg('INFO:{}'.format(datetime.now())))
        chdir(path.expanduser("~"))

    def finish(self):
        ' clear when finish '
        self.process.kill()
예제 #5
0
class Main(plugin.Plugin):
    " Main Class "
    def initialize(self, *args, **kwargs):
        " Init Main Class "
        super(Main, self).initialize(*args, **kwargs)
        self.completer, self.dirs = QCompleter(self), QDirModel(self)
        self.dirs.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot)
        self.completer.setModel(self.dirs)
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setCompletionMode(QCompleter.PopupCompletion)
        self.process, self.mainwidget = QProcess(), QTabWidget()
        self.process.readyReadStandardOutput.connect(self.readOutput)
        self.process.readyReadStandardError.connect(self.readErrors)
        self.process.finished.connect(self._process_finished)
        self.process.error.connect(self._process_finished)
        self.mainwidget.tabCloseRequested.connect(lambda:
            self.mainwidget.setTabPosition(1)
            if self.mainwidget.tabPosition() == 0
            else self.mainwidget.setTabPosition(0))
        self.mainwidget.setStyleSheet('QTabBar{font-weight:bold;}')
        self.mainwidget.setMovable(True)
        self.mainwidget.setTabsClosable(True)
        self.dock, self.scrollable = QDockWidget(), QScrollArea()
        self.scrollable.setWidgetResizable(True)
        self.scrollable.setWidget(self.mainwidget)
        self.dock.setWindowTitle(__doc__)
        self.dock.setStyleSheet('QDockWidget::title{text-align: center;}')
        self.dock.setWidget(self.scrollable)
        self.locator.get_service('misc').add_widget(self.dock,
                                 QIcon.fromTheme("face-sad"), __doc__)
        self.tab1, self.tab2, self.tab3 = QGroupBox(), QGroupBox(), QGroupBox()
        self.tab4, self.tab5, self.tab6 = QGroupBox(), QGroupBox(), QGroupBox()
        for a, b in ((self.tab1, 'Basics'), (self.tab2, 'Coverage'),
            (self.tab3, 'Extensions'), (self.tab5, 'Regex'),
             (self.tab4, 'Paths'), (self.tab6, 'Run')):
            a.setTitle(b)
            a.setToolTip(b)
            self.mainwidget.addTab(a, QIcon.fromTheme("face-sad"), b)
        QPushButton(QIcon.fromTheme("help-about"), 'About', self.dock
          ).clicked.connect(lambda: QMessageBox.information(self.dock, __doc__,
          ''.join((__doc__, __version__, __license__, 'by', __author__))))

        groupl, groupr, co = QWidget(), QWidget(), QGroupBox()
        self.qckb1 = QCheckBox('Open target directory later')
        self.qckb2 = QCheckBox('Save a LOG file to target later')
        self.qckb3 = QCheckBox('Verbose operation')
        self.qckb4 = QCheckBox('Force Stop on Error')
        self.qckb5 = QCheckBox('Scan Executable files for Tests')
        vboxgl, vboxgr = QVBoxLayout(groupl), QVBoxLayout(groupr)
        for a in (self.qckb1, self.qckb2, self.qckb3, self.qckb4, self.qckb5):
            vboxgl.addWidget(a)
            a.setToolTip(a.text())
        self.qckb6 = QCheckBox('No Byte Compile to .PYC or Delete .PYC later')
        self.qckb7 = QCheckBox('Dont touch sys.path when running tests')
        self.qckb8 = QCheckBox('Traverse all paths of a package')
        self.qckb9 = QCheckBox('Dont capture STDOUT, print STDOUT on the fly')
        self.qckb10 = QCheckBox('Clear all Logging handlers')
        for a in (self.qckb6, self.qckb7, self.qckb8, self.qckb9, self.qckb10):
            vboxgr.addWidget(a)
            a.setToolTip(a.text())
        vboxcon, self.framew = QHBoxLayout(co), QComboBox()
        [vboxcon.addWidget(a) for a in (groupl, groupr)]
        self.chrt = QCheckBox('LOW CPU priority for Backend Process')
        self.framew.addItems(['nosetests', 'PyTest', 'DocTest', 'Unittest',
                              'Django_Test', 'Django-Nose', 'None'])
        self.framew.currentIndexChanged.connect(lambda:  #FIXME refactor for 3
            QMessageBox.information(self.dock, __doc__, '<b>Only Nose for now'))
        self.framew.currentIndexChanged.connect(lambda:  #FIXME refactor for 3
            self.framew.setCurrentIndex(0))
        vboxg1 = QVBoxLayout(self.tab1)
        for each_widget in (QLabel('<b>Framework'), self.framew, self.chrt, co):
            vboxg1.addWidget(each_widget)

        self.t2ck1, self.t2sp1 = QCheckBox('Activate Coverage'), QSpinBox()
        self.t2ck2 = QCheckBox('Erase previously collected Coverage before run')
        self.t2ck3 = QCheckBox('Include all tests modules in Coverage reports')
        self.t2ck4 = QCheckBox('Include all python files on working directory')
        self.t2ck5 = QCheckBox('Produce HTML Coverage reports information')
        self.t2ck6 = QCheckBox('Include Branch Coverage in Coverage reports')
        self.t2sp1.setRange(10, 90)
        self.t2sp1.setValue(75)
        vboxg2 = QVBoxLayout(self.tab2)
        for each_widget in (QLabel('<b>Min Percentage'), self.t2sp1, self.t2ck1,
            self.t2ck2, self.t2ck3, self.t2ck4, self.t2ck5, self.t2ck6):
            vboxg2.addWidget(each_widget)

        groupi, groupd, vbxg3 = QGroupBox(), QGroupBox(), QHBoxLayout(self.tab3)
        vboxgi, vboxgd = QVBoxLayout(groupi), QVBoxLayout(groupd)
        self.t3ck1 = QCheckBox('Activate DocTest to find and run doctests')
        self.t3ck2 = QCheckBox('Look for any doctests in tests modules too')
        self.t3ck3 = QCheckBox('Activate isolation (Do Not use with Coverage!)')
        self.t3ck4 = QCheckBox('Use Detailed Errors, evaluate failed asserts')
        for a in (self.t3ck1, self.t3ck2, self.t3ck3, self.t3ck4):
            vboxgi.addWidget(a)
            a.setToolTip(a.text())
        self.t3ck5 = QCheckBox('Disable special handling of SkipTest exception')
        self.t3ck6 = QCheckBox('Run the tests that failed in the last test run')
        self.t3ck7 = QCheckBox('Use AllModules, Collect tests from all modules')
        self.t3ck8 = QCheckBox('Collect tests names only, do Not run any tests')
        for a in (self.t3ck5, self.t3ck6, self.t3ck7, self.t3ck8):
            vboxgd.addWidget(a)
            a.setToolTip(a.text())
        [vbxg3.addWidget(a) for a in (groupi, groupd)]

        self.t4le1, self.t4le2 = QLineEdit(), QLineEdit(path.expanduser("~"))
        self.t4le1.setCompleter(self.completer)
        self.t4le2.setCompleter(self.completer)
        self.t4le1.setPlaceholderText(' /full/path/to/a/folder/ ')
        self.t4le2.setPlaceholderText(' /full/path/to/a/folder/ ')
        le1b = QPushButton(QIcon.fromTheme("folder-open"), 'Open')
        le1b.setMinimumSize(50, 50)
        le1b.clicked.connect(lambda: self.t4le1.setText(
            QFileDialog.getExistingDirectory(None, '', path.expanduser("~"))))
        le2b = QPushButton(QIcon.fromTheme("folder-open"), 'Open')
        le2b.clicked.connect(lambda: self.t4le2.setText(
            QFileDialog.getExistingDirectory(None, '', path.expanduser("~"))))
        vboxg4 = QVBoxLayout(self.tab4)
        for a in (QLabel('<b>Directory to look for Tests'), self.t4le1, le1b,
            QLabel('<b>Directory to generate HTML Coverage'), self.t4le2, le2b):
            vboxg4.addWidget(a)
            a.setToolTip(a.text())

        self.t5le1 = QLineEdit(r'(?:^|[\b_\./-])[Tt]est')
        self.t5le2 = QLineEdit()
        self.t5le3, vboxg5 = QLineEdit(), QVBoxLayout(self.tab5)
        r = QPushButton('Reset')
        r.clicked.connect(lambda: self.t5le1.setText(r'(?:^|[\b_\./-])[Tt]est'))
        for a in (QLabel('<b>Matching Name Regex to be test'), self.t5le1, r,
            QLabel('<b>Force Include Regex Tests'), self.t5le2,
            QLabel('<b>Force Exclude Regex Tests'), self.t5le3):
            vboxg5.addWidget(a)
            a.setToolTip(a.text())

        self.output = QTextEdit(''' Engineering is the art of making what you
            want from things you can get.    -Dhobi''')
        self.runbtn = QPushButton(QIcon.fromTheme("face-sad"), 'Start Testing!')
        self.runbtn.setMinimumSize(75, 50)
        self.runbtn.clicked.connect(self.run)
        glow = QGraphicsDropShadowEffect(self)
        glow.setOffset(0)
        glow.setBlurRadius(99)
        glow.setColor(QColor(99, 255, 255))
        self.runbtn.setGraphicsEffect(glow)
        self.kbt = QPushButton(QIcon.fromTheme("application-exit"), 'Kill')
        self.kbt.clicked.connect(lambda: self.process.kill())
        vboxg6 = QVBoxLayout(self.tab6)
        for each_widget in (QLabel('Logs'), self.output, self.runbtn, self.kbt):
            vboxg6.addWidget(each_widget)
        [a.setChecked(True) for a in (self.chrt, self.qckb2, self.qckb3,
                                      self.qckb10, self.t2ck1, self.t2ck2,
                                      self.t2ck5, self.t3ck1, self.t3ck4)]
        self.mainwidget.setCurrentIndex(4)

    def readOutput(self):
        """Read and append output to the logBrowser"""
        self.output.append(str(self.process.readAllStandardOutput()))

    def readErrors(self):
        """Read and append errors to the logBrowser"""
        self.output.append(str(self.process.readAllStandardError()))

    def run(self):
        """Main function calling vagrant to generate the vm"""
        if not len(self.t4le1.text()):
            QMessageBox.information(self.dock, __doc__,
                '<b style="color:red">ERROR: Target Folder can not be Empty !')
            return
        self.output.clear()
        self.output.append('INFO: OK: Starting at {}'.format(datetime.now()))
        self.runbtn.setDisabled(True)
        #nose = True if self.framew.currentText() in 'nosetests' else False
        cmd = ' '.join(('chrt -i 0' if self.chrt.isChecked() else '',
            # tab 1
            self.framew.currentText(),
            '--verbose' if self.qckb3.isChecked() else '--quiet',
            '--stop' if self.qckb4.isChecked() else '',
            '--exe' if self.qckb5.isChecked() else '--noexe',
            '--no-byte-compile' if self.qckb6.isChecked() else '',
            '--no-path-adjustment' if self.qckb7.isChecked() else '',
            '--traverse-namespace' if self.qckb8.isChecked() else '',
            '--nocapture' if self.qckb9.isChecked() else '',
            '--logging-clear-handlers' if self.qckb10.isChecked() else '',
            # tab 2
            '--with-coverage' if self.t2ck1.isChecked() else '',
            '--cover-erase' if self.t2ck2.isChecked() else '',
            '--cover-tests' if self.t2ck3.isChecked() else '',
            '--cover-inclusive' if self.t2ck4.isChecked() else '',
            '--cover-html' if self.t2ck5.isChecked() else '--cover-xml',
            '--cover-branches' if self.t2ck6.isChecked() else '',
            '--cover-min-percentage={}'.format(self.t2sp1.value()),
            # tab 3
            '--with-doctest' if self.t3ck1.isChecked() else '',
            '--doctest-tests' if self.t3ck2.isChecked() else '',
            '--with-isolation' if self.t3ck3.isChecked() else '',
            '--detailed-errors' if self.t3ck4.isChecked() else '',
            '--no-skip' if self.t3ck5.isChecked() else '',
            '--failed' if self.t3ck6.isChecked() else '',
            '--all-modules' if self.t3ck7.isChecked() else '',
            '--collect-only' if self.t3ck8.isChecked() else '',
            # tab 4
            '--where="{}"'.format(self.t4le1.text()),
            '--cover-html-dir="{}"'.format(self.t4le2.text()) if self.t2ck5.isChecked() else '--cover-xml-file={}'.format(path.join(self.t4le2.text(), 'coverage_ninja.xml')),
            # tab 5
            '--match="{}"'.format(self.t5le1.text().encode('utf-8')) if len(self.t5le1.text()) else '',
            '--include="{}"'.format(self.t5le2.text()) if len(self.t5le2.text()) else '',
            '--exclude="{}"'.format(self.t5le3.text()) if len(self.t5le3.text()) else '',
        ))
        self.output.append('INFO: OK: Command: {}'.format(cmd))
        with open(path.join(self.t4le2.text(), 'tests_run_ninja.sh'), 'w') as f:
            self.output.append('INFO: OK : Writing tests_run_ninja.sh')
            f.write('#!/usr/bin/env bash\n# -*- coding: utf-8 -*-\n\n' + cmd)
        try:
            chmod(path.join(self.t4le2.text(), 'tests_run_ninja.sh'), 0775)
        except:
            chmod(path.join(self.t4le2.text(), 'tests_run_ninja.sh'), 0o775)
        self.output.append('INFO: OK: Running Tests !')
        self.process.start(cmd)
        if not self.process.waitForStarted():
            self.output.append('ERROR: FAIL: Unkown Error !')
            self.runbtn.setEnabled(True)
            return
        self.runbtn.setEnabled(True)

    def _process_finished(self):
        """finished sucessfully"""
        self.output.append('INFO: OK: Finished at {}'.format(datetime.now()))
        if self.qckb2.isChecked() is True:
            with open(path.join(self.t4le2.text(), 'test_ninja.log'), 'w') as f:
                self.output.append('INFO: OK: Writing .LOG')
                f.write(self.output.toPlainText())
        if self.qckb1.isChecked() is True:
            self.output.append('INFO:Opening Target Folder')
            try:
                startfile(self.t4le2.text())
            except:
                Popen(["xdg-open", self.t4le2.text()])

    def finish(self):
        ' clear when finish '
        self.process.kill()
예제 #6
0
class Main(plugin.Plugin):
    " Main Class "
    def initialize(self, *args, **kwargs):
        " Init Main Class "
        super(Main, self).initialize(*args, **kwargs)
        self.process = QProcess()
        self.process.readyReadStandardOutput.connect(self.readOutput)
        self.process.readyReadStandardError.connect(self.readErrors)
        self.process.finished.connect(self._process_finished)
        self.process.error.connect(self._process_finished)
        self.editor_s = self.locator.get_service('editor')
        self.completer, self.dirs = QCompleter(self), QDirModel(self)
        self.dirs.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot)
        self.completer.setModel(self.dirs)
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setCompletionMode(QCompleter.PopupCompletion)

        self.group0 = QGroupBox()
        self.group0.setTitle(' Source ')
        self.infile = QLineEdit(path.expanduser("~"))
        self.infile.setPlaceholderText(' /full/path/to/file.html ')
        self.infile.setCompleter(self.completer)
        self.open = QPushButton(QIcon.fromTheme("folder-open"), 'Open')
        self.open.setCursor(QCursor(Qt.PointingHandCursor))
        self.open.clicked.connect(lambda: self.infile.setText(str(
            QFileDialog.getOpenFileName(self.dock, "Open a File to read from",
            path.expanduser("~"), ';;'.join(['{}(*.{})'.format(e.upper(), e)
            for e in ['py', 'pyw', 'txt', '*']])))))
        self.output = QTextEdit()
        vboxg0 = QVBoxLayout(self.group0)
        for each_widget in (self.infile, self.open, self.output):
            vboxg0.addWidget(each_widget)

        self.group1 = QGroupBox()
        self.group1.setTitle(' General ')
        self.group1.setCheckable(True)
        self.group1.setGraphicsEffect(QGraphicsBlurEffect(self))
        self.group1.graphicsEffect().setEnabled(False)
        self.group1.toggled.connect(self.toggle_gral_group)
        self.ckgrl1 = QCheckBox('Create standalone executable')
        self.ckgrl2 = QCheckBox('Use Python debug')
        self.ckgrl3 = QCheckBox('Force compilation for MS Windows')
        self.ckgrl4 = QCheckBox('When compiling, disable the console window')
        self.ckgrl5 = QCheckBox('Use link time optimizations if available')
        self.ckgrl6 = QCheckBox('Force the use of clang')
        self.ckgrl7 = QCheckBox('Allow minor devitations from Python behaviour')
        self.ckgrl8 = QCheckBox('Warnings implicit exceptions at compile time')
        self.pyver, self.jobs = QComboBox(), QSpinBox()
        self.pyver.addItems(['2.7', '2.6', '3.2', '3.3'])
        self.jobs.setValue(1)
        self.jobs.setMaximum(12)
        self.jobs.setMinimum(1)
        vboxg1 = QVBoxLayout(self.group1)
        for each_widget in (self.ckgrl1, self.ckgrl2, self.ckgrl3, self.ckgrl4,
            self.ckgrl5, self.ckgrl6, self.ckgrl7, self.ckgrl8,
            QLabel('Python Version to Target'), self.pyver,
            QLabel('Multi-Processing Parallel Workers'), self.jobs):
            vboxg1.addWidget(each_widget)
            try:
                each_widget.setToolTip(each_widget.text())
            except:
                pass

        self.group2 = QGroupBox()
        self.group2.setTitle(' Recursion Control ')
        self.ckrec0 = QCheckBox('Descend to imported modules from standard lib')
        self.ckrec1 = QCheckBox('Force not descend to any imported modules')
        self.ckrec2 = QCheckBox('Try to descend into all imported modules')
        vboxg2 = QVBoxLayout(self.group2)
        for each_widget in (self.ckrec0, self.ckrec1, self.ckrec2):
            vboxg2.addWidget(each_widget)
            each_widget.setToolTip(each_widget.text())

        self.group3 = QGroupBox()
        self.group3.setTitle(' Execution after compilation ')
        self.ckexe0 = QCheckBox('Execute created binary (or import the module)')
        self.ckexe1 = QCheckBox('When executing binary dont reset PYTHONPATH')
        vboxg2 = QVBoxLayout(self.group3)
        for each_widget in (self.ckexe0, self.ckexe1):
            vboxg2.addWidget(each_widget)
            each_widget.setToolTip(each_widget.text())

        self.group4, self.dumptree = QGroupBox(), QTextEdit()
        self.group4.setTitle(' Dump of internal tree ')
        QVBoxLayout(self.group4).addWidget(self.dumptree)

        self.group5 = QGroupBox()
        self.group5.setTitle(' Code generation ')
        self.chdmp1 = QCheckBox('Statements shall have their line numbers set')
        self.chdmp2 = QCheckBox('Disable all unnecessary Python optimization')
        vboxg5 = QVBoxLayout(self.group5)
        for each_widget in (self.chdmp1, self.chdmp2):
            vboxg5.addWidget(each_widget)
            each_widget.setToolTip(each_widget.text())

        self.group6 = QGroupBox()
        self.group6.setTitle(' Output ')
        self.outdir = QLineEdit(path.expanduser("~"))
        self.outdir.setPlaceholderText(' /full/path/to/target/directory ')
        self.outdir.setCompleter(self.completer)
        self.open2 = QPushButton(QIcon.fromTheme("folder-open"), 'Open')
        self.open2.setCursor(QCursor(Qt.PointingHandCursor))
        self.open2.clicked.connect(lambda: self.outdir.setText(str(
            QFileDialog.getExistingDirectory(self.dock, "Open Target Folder",
            path.expanduser("~")))))
        self.ckcgn2 = QCheckBox('Remove build dir after compile module or exe')
        vboxg6 = QVBoxLayout(self.group6)
        for each_widget in (QLabel('Target Output Directory'), self.outdir,
                            self.open2, self.ckcgn2):
            vboxg6.addWidget(each_widget)
            each_widget.setToolTip(each_widget.text())

        self.group7 = QGroupBox()
        self.group7.setTitle(' Debug ')
        self.ckdbg1 = QCheckBox('Execute self checks to find errors in Nuitka')
        self.ckdbg2 = QCheckBox('Keep debug info in resulting file')
        self.ckdbg3 = QCheckBox('Traced execution output')
        self.ckdbg4 = QCheckBox('Allow compile edited C++ file, debug changes')
        self.ckdbg5 = QCheckBox('Use experimental features')
        vboxg7 = QVBoxLayout(self.group7)
        for each_widget in (self.ckdbg1, self.ckdbg2, self.ckdbg3,
                            self.ckdbg4, self.ckdbg5):
            vboxg7.addWidget(each_widget)
            each_widget.setToolTip(each_widget.text())

        self.group8 = QGroupBox()
        self.group8.setTitle(' Tracing ')
        self.cktrc1 = QCheckBox('Show Scons in non-quiet mode, showing command')
        self.cktrc2 = QCheckBox('Show Progress information and statistics')
        self.cktrc3 = QCheckBox('Show Verbose output details')
        vboxg8 = QVBoxLayout(self.group8)
        for each_widget in (self.cktrc1, self.cktrc2, self.cktrc3):
            vboxg8.addWidget(each_widget)
            each_widget.setToolTip(each_widget.text())

        self.group9 = QGroupBox()
        self.group9.setTitle(' Extras ')
        self.group9.setCheckable(True)
        self.group9.toggled.connect(self.group9.hide)
        self.nice = QSpinBox()
        self.nice.setValue(20)
        self.nice.setMaximum(20)
        self.nice.setMinimum(0)
        self.ckxtr1 = QCheckBox('Open Target Directory later')
        self.ckxtr2 = QCheckBox('Save a LOG file to target later')
        self.ckxtr3 = QCheckBox('Save SH Bash script to reproduce Nuitka build')
        try:
            self.vinfo = QLabel('<center> <b> Nuitka Backend Version: </b>' +
                            getoutput('nuitka --version',).strip())
        except:
            self.vinfo = QLabel('<b>Warning: Failed to query Nuitka Backend!')
        vboxg9 = QVBoxLayout(self.group9)
        for each_widget in (QLabel('Backend CPU Priority'), self.nice,
                            self.ckxtr1, self.ckxtr2, self.ckxtr3, self.vinfo):
            vboxg9.addWidget(each_widget)

        self.group10 = QGroupBox()
        self.group10.setTitle(' Documentation ')
        self.group10.setCheckable(True)
        self.group10.toggled.connect(self.group10.hide)
        vboxg10 = QVBoxLayout(self.group10)
        for each_widget in (QLabel('''<a href=
            "file:///usr/share/doc/nuitka/README.pdf.gz">
            <small><center> Nuitka User Documentation Local PDF </a>'''),
            QLabel('''<a href=
            "file:///usr/share/doc/nuitka/Developer_Manual.pdf.gz">
            <small><center> Nuitka Developer Documentation Local PDF </a>'''),
            QLabel('''<a href="http://nuitka.net/doc/user-manual.html">
            <small><center> Nuitka User Documentation On Line HTML </a>'''),
            QLabel('''<a href="http://nuitka.net/doc/developer-manual.html">
            <small><center> Nuitka Developer Documentation On Line HTML </a>''')
             ):
            vboxg10.addWidget(each_widget)
            each_widget.setOpenExternalLinks(True)
            each_widget.setTextInteractionFlags(Qt.LinksAccessibleByMouse)

        [a.setChecked(True) for a in (self.ckgrl1, self.ckgrl2, self.ckgrl4,
            self.ckgrl5, self.ckgrl6, self.ckgrl7, self.ckgrl8, self.ckrec0,
            self.ckrec1, self.ckrec2, self.ckexe1, self.ckcgn2, self.ckdbg1,
            self.ckdbg3, self.ckdbg4, self.ckdbg5, self.cktrc1, self.cktrc2,
            self.cktrc3, self.ckxtr1, self.ckxtr2, self.ckxtr3,)]

        self.button = QPushButton(QIcon.fromTheme("face-cool"),
                                  'Compile Python')
        self.button.setCursor(QCursor(Qt.PointingHandCursor))
        self.button.setMinimumSize(100, 50)
        self.button.clicked.connect(self.run)
        glow = QGraphicsDropShadowEffect(self)
        glow.setOffset(0)
        glow.setBlurRadius(99)
        glow.setColor(QColor(99, 255, 255))
        self.button.setGraphicsEffect(glow)

        class TransientWidget(QWidget):
            ' persistant widget thingy '
            def __init__(self, widget_list):
                ' init sub class '
                super(TransientWidget, self).__init__()
                vbox = QVBoxLayout(self)
                for each_widget in widget_list:
                    vbox.addWidget(each_widget)

        tw = TransientWidget((
            QLabel('<b>Python Code to Binary Executable Compiler'), self.group0,
            self.group6, self.group1, self.group2, self.group3, self.group4,
            self.group5, self.group7, self.group8, self.group9, self.group10,
            self.button, ))
        self.scrollable, self.dock = QScrollArea(), QDockWidget()
        self.scrollable.setWidgetResizable(True)
        self.scrollable.setWidget(tw)
        self.dock.setWindowTitle(__doc__)
        self.dock.setStyleSheet('QDockWidget::title{text-align: center;}')
        self.dock.setWidget(self.scrollable)
        ExplorerContainer().addTab(self.dock, "Nuitka")
        QPushButton(QIcon.fromTheme("help-about"), 'About', self.dock
          ).clicked.connect(lambda: QMessageBox.information(self.dock, __doc__,
            HELPMSG))

    def run(self):
        ' run the compile '
        target = path.abspath(str(self.infile.text()).strip())
        self.button.setDisabled(True)
        self.output.clear()
        self.output.show()
        self.output.setFocus()
        self.output.append(self.formatInfoMsg('INFO:{}'.format(datetime.now())))
        self.output.append(self.formatInfoMsg(' INFO: Dumping Internal Tree'))
        try:
            self.dumptree.setPlainText(
                getoutput('nuitka --dump-tree {}'.format(target)))
            self.dumptree.setMinimumSize(100, 500)
        except:
            self.output.append(self.formatErrorMsg('ERROR:FAIL: Internal Tree'))
        self.output.append(self.formatInfoMsg(' INFO: OK: Parsing Arguments'))
        cmd = ' '.join(('nice --adjustment={} nuitka'.format(self.nice.value()),

            # output
            '--remove-output' if self.ckcgn2.isChecked() is True else '',

            # general
            '--exe' if self.ckgrl1.isChecked() is True else '',
            '--python-debug' if self.ckgrl2.isChecked() is True else '',
            '--verbose' if self.cktrc3.isChecked() is True else '',
            '--windows-target' if self.ckgrl3.isChecked() is True else '',
            '--windows-disable-console' if self.ckgrl4.isChecked() is True else '',
            '--lto' if self.ckgrl5.isChecked() is True else '',
            '--clang' if self.ckgrl6.isChecked() is True else '',
            '--improved' if self.ckgrl7.isChecked() is True else '',
            '--warn-implicit-exceptions' if self.ckgrl8.isChecked() is True else '',

            # recursion control
            '--recurse-stdlib' if self.ckrec0.isChecked() is True else '',
            '--recurse-none' if self.ckrec1.isChecked() is True else '',
            '--recurse-all' if self.ckrec2.isChecked() is True else '',

            # execution after compilation
            '--execute' if self.ckexe0.isChecked() is True else '',
            '--keep-pythonpath' if self.ckexe1.isChecked() is True else '',

            # code generation
            '--code-gen-no-statement-lines' if self.chdmp1.isChecked() is True else '',
            '--no-optimization' if self.chdmp2.isChecked() is True else '',

            # debug
            '--debug' if self.ckdbg1.isChecked() is True else '',
            '--unstripped' if self.ckdbg2.isChecked() is True else '',
            '--trace-execution' if self.ckdbg3.isChecked() is True else '',
            '--c++-only' if self.ckdbg4.isChecked() is True else '',
            '--experimental' if self.ckdbg5.isChecked() is True else '',

            # tracing
            '--show-scons' if self.cktrc1.isChecked() is True else '',
            '--show-progress' if self.cktrc2.isChecked() is True else '',
            '--verbose' if self.cktrc3.isChecked() is True else '',

            # non boolean parametrization
            '--python-version={}'.format(self.pyver.currentText()),
            '--jobs={}'.format(self.jobs.value()),
            '--output-dir="{}"'.format(self.outdir.text()),
            target))
        self.output.append(self.formatInfoMsg(' INFO: Command: {}'.format(cmd)))
        self.output.append(self.formatInfoMsg(' INFO: OK: Starting to Compile'))
        self.process.start(cmd)
        if not self.process.waitForStarted():
            self.output.append(self.formatErrorMsg('ERROR: FAIL: Compile Fail'))
            self.output.append(self.formatErrorMsg('ERROR:FAIL:{}'.format(cmd)))
            self.button.setEnabled(True)
            return
        # write a .sh bash script file on target
        if self.ckxtr3.isChecked() is True:
            sh_file = 'nuitka_compile_python_to_cpp.sh'
            with open(path.join(str(self.outdir.text()), sh_file), 'w') as _sh:
                self.output.append(self.formatInfoMsg('''INFO: OK: Writing Bash:
                    {}'''.format(sh_file)))
                _sh.write('#!/usr/bin/env bash {}{}'.format(linesep, cmd))
                _sh.close()
            self.output.append(self.formatInfoMsg('INFO: OK: Bash chmod: 775'))
            try:
                chmod(path.join(str(self.outdir.text()), sh_file), 0775)  # Py2
            except:
                chmod(path.join(str(self.outdir.text()), sh_file), 0o775)  # Py3

    def _process_finished(self):
        """sphinx-build finished sucessfully"""
        self.output.append(self.formatInfoMsg('INFO:{}'.format(datetime.now())))
        if self.ckxtr2.isChecked() is True:
            log_file = 'nuitka_ninja.log'
            with open(path.join(str(self.outdir.text()), log_file), 'w') as log:
                self.output.append(self.formatInfoMsg('''INFO: OK: Writing LOG:
                    {}'''.format(log_file)))
                log.write(self.output.toPlainText())
        if self.ckxtr1.isChecked() is True:
            try:
                startfile(path.abspath(str(self.outdir.text())))
            except:
                Popen(["xdg-open", path.abspath(str(self.outdir.text()))])
        self.button.setDisabled(False)
        self.output.show()
        self.output.setFocus()
        self.output.selectAll()

    def toggle_gral_group(self):
        ' toggle on or off the checkboxes '
        if self.group1.isChecked() is True:
            [a.setChecked(True) for a in (self.ckgrl1, self.ckgrl2, self.ckgrl4,
            self.ckgrl5, self.ckgrl6, self.ckgrl7, self.ckgrl8)]
            self.group1.graphicsEffect().setEnabled(False)
        else:
            [a.setChecked(False) for a in (self.ckgrl1, self.ckgrl2,
            self.ckgrl4, self.ckgrl5, self.ckgrl6, self.ckgrl7, self.ckgrl8)]
            self.group1.graphicsEffect().setEnabled(True)

    def readOutput(self):
        """Read and append sphinx-build output to the logBrowser"""
        self.output.append(str(self.process.readAllStandardOutput()))

    def readErrors(self):
        """Read and append sphinx-build errors to the logBrowser"""
        self.output.append(self.formatErrorMsg(str(
                                        self.process.readAllStandardError())))

    def formatErrorMsg(self, msg):
        """Format error messages in red color"""
        return self.formatMsg(msg, 'red')

    def formatInfoMsg(self, msg):
        """Format informative messages in blue color"""
        return self.formatMsg(msg, 'green')

    def formatMsg(self, msg, color):
        """Format message with the given color"""
        return '<font color="{}">{}</font>'.format(color, msg)