class MainWindow(QMainWindow):
    """Fenêtre principale du programme"""
    # Fichiers
    grubFonctionsFile = path("fonctions_iso.cfg")
    # Insctructions
    customIncipit = "source ${prefix}/greffons/fonctions_iso.cfg\n"
    grubConf = ("if [ -f  ${config_directory}/custom.cfg ]; then\n"
                "  source ${config_directory}/custom.cfg\n"
                'elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then\n'
                "  source $prefix/custom.cfg;\n"
                "fi\n")
    
    def __init__(self, allowTemp=True):
        QMainWindow.__init__(self)
        
        # Création des éléments
        # Left
        self.customEditor = CustomEditor("/boot/grub")
        if allowTemp:
            self.options = Options(self)
        else:
            self.options = None
        # Right
        self.editor = Editor(self)
        valid = QPushButton("Valider")
        valid.clicked.connect(self.valid)
        cancel = QPushButton("Quitter")
        cancel.clicked.connect(qApp.quit)
        # Top
        menubar = self.menuBar()
        
        # Création des Layout
        # Boutons
        buttons = QHBoxLayout()
        buttons.addWidget(valid)
        buttons.addWidget(cancel)
        # Left
        left = QVBoxLayout()
        left.addWidget(self.customEditor)
        if self.options:
            left.addWidget(self.options)
        leftW = QWidget()
        leftW.setLayout(left)
        # Right
        right = QVBoxLayout()
        right.addWidget(self.editor)
        right.addLayout(buttons)
        rightW = QWidget()
        rightW.setLayout(right)
        # Window
        window = QSplitter()
        window.addWidget(leftW)
        window.addWidget(rightW)
        self.setCentralWidget(window)
        
        # Création des menus
        # Fichier
        quit = QAction("Quitter", self)
        quit.setShortcut('Ctrl+Q')
        quit.triggered.connect(qApp.quit)
        openISO = QAction("Sélectionner une ISO", self)
        openISO.triggered.connect(self.editor.open_iso)
        openLoop = QAction("Ouvrir un fichier loopback", self)
        openLoop.triggered.connect(self.editor.open_loopback)
        fileMenu = menubar.addMenu("Fichier")
        fileMenu.addAction(openISO)
        fileMenu.addAction(openLoop)
        fileMenu.addAction(quit)
        # Loopback
        genLoop = QAction("Générer le fichier loopback", self)
        genLoop.triggered.connect(self.editor.gen_loopback)
        setFrench = QAction('Ajouter les traductions françaises', self)
        setFrench.triggered.connect(self.editor.addFrenchTranslations)
        loopMenu = menubar.addMenu("Loopback")
        loopMenu.addAction(genLoop)
        loopMenu.addAction(setFrench)
        
        # Signaux
        self.customEditor.currentItemChanged.connect(self.updateDisplay)
        self.editor.iso_location.textChanged.connect(self.customEditor.setIsoLocation)
        self.editor.textChanged.connect(self.customEditor.setLoopbackContent)
        if self.options:
            self.options.permanentCB.stateChanged.connect(self.customEditor.setPermanent)
            
        # Initialisation de l'interface
        self.setWindowTitle("GrubEnhancer")
        self.updateDisplay(self.customEditor.getCurrent())
        
    @pyqtSlot(CustomEntry)
    def updateDisplay(self, entry):
        # Obtention des paramètres de l'entrée
        mountpoint = entry.getMountPoint()
        isoLocation = path(mountpoint) / entry.getIsoLocation()[1:]
        loopbackContent = entry.getLoopbackContent()
        permanent = entry.getPermanent()
        enabled = entry.getEnabled()
        # Mise à jour de l'interface
        self.editor.loopback_edit.setPlainText(loopbackContent)
        self.editor.iso_location.setText(isoLocation)
        if self.options:
            if permanent:
                self.options.permanentCB.setCheckState(Qt.Checked)
            else:
                self.options.permanentCB.setCheckState(Qt.Unchecked)
        if isoLocation.exists():
            entry.setEnabled(True)
            self.editor.setEnabled(True)
            if self.options:
                self.options.setEnabled(True)
        else:
            entry.setEnabled(False)
            self.editor.setEnabled(False)
            if self.options:
                self.options.setEnabled(False)
    
    def valid(self):
        """Lance la procédure de mise à jour de Grub,
        après avoir vérifié que tous les paramètres
        étaient bien donnés"""
        cache = self.customEditor.getCache()
        entries = cache["/boot/grub"]
        grubRep = path("/boot/grub")
        # Mise à jour de la config de GRUB
        grub_config_file = path("/boot/grub/grub.cfg")
        if self.grubConf not in grub_config_file.text():
            grub_config_file.write_text("### BEGIN GrubEnhancer Config ###\n" + self.grubConf + "### END GrubEnhancer Config ###\n", append=True)
        # Écriture des fonctions GRUB
        greffons = path("/boot/grub/greffons")
        if not greffons.isdir():
            greffons.mkdir()
        fonctionsFile = "/boot/grub/greffons/fonctions_iso.cfg"
        self.grubFonctionsFile.copy(fonctionsFile)
        # Création des Loopback et du Custom
        custom = path("/boot/grub/custom.cfg")
        custom_content = [self.customIncipit]
        for entry in entries:
            # Récupération des paramètres
            name = entry.text()
            iso_location = entry.getIsoLocation()
            print(iso_location)
            loopback_content = entry.getLoopbackContent()
            loopback_location = iso_location.replace('.iso', '.loopback.cfg')
            mountpoint = entry.getMountPoint()
            permanent = entry.getPermanent()
            # Création du Loopback
            print(iso_location, loopback_location, mountpoint, sep=" : ")
            temporary = False
            if loopback_content:
                full_loopback_location = path(mountpoint) / loopback_location[1:] # On vire toujours le premier /
                full_loopback_location.write_text(loopback_content)
            # Création d'une ligne du Custom
            if permanent:
                if loopback_content:
                    custom_line = '\tsubmenu "' + name + '" {iso_boot "' + iso_location + '" "' + loopback_location + '"} #' + mountpoint + '\n'
                else:
                    custom_line = '\tsubmenu "' + name + '" {iso_boot "' + iso_location + '"} #' + mountpoint + '\n'
            else:
                if loopback_content:
                    custom_line = 'amorce_iso "{}" "{}" #{}\n'.format(iso, loopback, mountpoint)
                else:
                    custom_line = 'amorce_iso "{}" #{}\n'.format(iso, mountpoint)
                temporary = True
            custom_content.append(custom_line)
        # Création du Custom
        custom.write_lines(custom_content)
        # Affichage d'un message de confirmation
        msg = "Vos modifications ont bien été prises en compte."
        info = QMessageBox(self)
        info.setWindowTitle("GrubEnhancer")
        info.setText(msg)
        info.exec_()
Exemplo n.º 2
0
class MainWindow(QMainWindow):
    """Fenêtre principale du programme"""
    # Fichiers
    grubFonctionsFile = path("fonctions_iso.cfg")
    # Insctructions
    customIncipit = "source ${prefix}/greffons/fonctions_iso.cfg\n"
    grubConf = ("if [ -f  ${config_directory}/custom.cfg ]; then\n"
                "  source ${config_directory}/custom.cfg\n"
                'elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then\n'
                "  source $prefix/custom.cfg;\n"
                "fi\n")
    
    def __init__(self, grubDir="/boot/grub"):
        QMainWindow.__init__(self)
        # Variables
        self.grubDir = path(grubDir)
        
        # Création des éléments
        # Left
        grubButton = QPushButton("Choisir un répertoire GRUB")
        grubButton.clicked.connect(self.chooseAnotherGrubDir)
        self.customEditor = CustomEditor()
        self.options = Options(self)
        # Right
        self.editor = Editor(self)
        valid = QPushButton("Valider")
        valid.clicked.connect(self.valid)
        cancel = QPushButton("Quitter")
        cancel.clicked.connect(qApp.quit)
        # Top
        menubar = self.menuBar()
        
        # Création des Layout
        # Boutons
        buttons = QHBoxLayout()
        buttons.addWidget(valid)
        buttons.addWidget(cancel)
        # Left
        left = QVBoxLayout()
        left.addWidget(grubButton)
        left.addWidget(self.customEditor)
        left.addWidget(self.options)
        leftW = QWidget()
        leftW.setLayout(left)
        # Right
        right = QVBoxLayout()
        right.addWidget(self.editor)
        right.addLayout(buttons)
        rightW = QWidget()
        rightW.setLayout(right)
        # Window
        window = QSplitter()
        window.addWidget(leftW)
        window.addWidget(rightW)
        self.setCentralWidget(window)
        
        # Création des menus
        # Fichier
        quit = QAction("Quitter", self)
        quit.setShortcut('Ctrl+Q')
        quit.triggered.connect(qApp.quit)
        openISO = QAction("Sélectionner une ISO", self)
        openISO.triggered.connect(self.editor.open_iso)
        openLoop = QAction("Ouvrir un fichier loopback", self)
        openLoop.triggered.connect(self.editor.open_loopback)
        fileMenu = menubar.addMenu("Fichier")
        fileMenu.addAction(openISO)
        fileMenu.addAction(openLoop)
        fileMenu.addAction(quit)
        # Loopback
        genLoop = QAction("Générer le fichier loopback", self)
        genLoop.triggered.connect(self.editor.gen_loopback)
        setFrench = QAction('Ajouter les traductions françaises', self)
        setFrench.triggered.connect(self.editor.addFrenchTranslations)
        loopMenu = menubar.addMenu("Loopback")
        loopMenu.addAction(genLoop)
        loopMenu.addAction(setFrench)
        
        # Signaux
        self.customEditor.currentItemChanged.connect(self.updateDisplay)
        self.editor.iso_location.textChanged.connect(self.customEditor.setIsoLocation)
        self.editor.textChanged.connect(self.customEditor.setLoopbackContent)
        self.options.permanentCB.stateChanged.connect(self.customEditor.setPermanent)
            
        # Initialisation de l'interface
        self.setWindowTitle("GrubEnhancer")
        self.loadGrubDir()
        self.updateDisplay(self.customEditor.getCurrent())
        
    @pyqtSlot(CustomEntry)
    def updateDisplay(self, entry):
        # Obtention des paramètres de l'entrée
        mountpoint = path(entry.getMountPoint())
        isoLocation = mountpoint / entry.getIsoLocation()[1:]
        loopbackContent = entry.getLoopbackContent()
        permanent = entry.getPermanent()
        enabled = entry.getEnabled()
        # Mise à jour de l'interface
        self.editor.loopback_edit.setPlainText(loopbackContent)
        self.editor.iso_location.setText(isoLocation)
        if permanent:
            self.options.permanentCB.setCheckState(Qt.Checked)
        else:
            self.options.permanentCB.setCheckState(Qt.Unchecked)
        if isoLocation.exists():
            entry.setEnabled(True)
            self.editor.setEnabled(True)
            self.options.setEnabled(True)
        else:
            entry.setEnabled(False)
            self.editor.setEnabled(False)
            self.options.setEnabled(False)
    
    @pyqtSlot()
    def valid(self):
        """Lance la procédure de mise à jour de Grub,
        après avoir vérifié que tous les paramètres
        étaient bien donnés"""
        cache = self.customEditor.getCache()
        entries = cache[self.grubDir]
        # Mise à jour de la config de GRUB
        grub_config_file = self.grubDir / "grub.cfg"
        if self.grubConf not in grub_config_file.text():
            grub_config_file.write_text("### BEGIN GrubEnhancer Config ###\n" + self.grubConf + "### END GrubEnhancer Config ###\n", append=True)
        # Écriture des fonctions GRUB
        greffons = self.grubDir / "greffons"
        if not greffons.isdir():
            greffons.mkdir()
        fonctionsFile = greffons / "fonctions_iso.cfg"
        self.grubFonctionsFile.copy(fonctionsFile)
        # Création des Loopback et du Custom
        custom = self.grubDir / "custom.cfg"
        custom_content = [self.customIncipit]
        temporary = False
        for entry in entries:
            # Récupération des paramètres
            name = entry.text()
            if name == "<New>":
                continue
            iso_location = path(entry.getIsoLocation())
            print(iso_location)
            loopback_content = entry.getLoopbackContent()
            loopback_location = path(iso_location.replace('.iso', '.loopback.cfg'))
            mountpoint = path(entry.getMountPoint())
            permanent = entry.getPermanent()
            # Création d'un lien si espaces
            if " " in iso_location:
                # Création d'un lien pour l'iso
                full_iso_location = mountpoint / iso_location[1:]
                symlink_iso = mountpoint / iso_location.basename()
                try:
                    full_iso_location.link(symlink_iso)
                except FileExistsError: pass
                iso_location = symlink_iso.replace(mountpoint, "", 1)
            # Création du Loopback
            print(iso_location, loopback_location, mountpoint, sep=" : ")
            if loopback_content:
                full_loopback_location = mountpoint / loopback_location[1:] # On vire toujours le premier /
                full_loopback_location.write_text(loopback_content)
                if " " in loopback_location:
                    # Création d'un lien pour le loopback
                    symlink_loopback = mountpoint / loopback_location.basename()
                    try:
                        full_loopback_location.link(symlink_loopback)
                    except FileExistsError: pass
                    loopback_location = symlink_loopback.replace(mountpoint, "", 1)
            # Création d'une ligne du Custom
            if permanent:
                if loopback_content:
                    custom_line = '\tsubmenu "' + name + '" {iso_boot "' + iso_location + '" "' + loopback_location + '"} #' + mountpoint + '\n'
                else:
                    custom_line = '\tsubmenu "' + name + '" {iso_boot "' + iso_location + '"} #' + mountpoint + '\n'
            else:
                if loopback_content:
                    custom_line = 'amorce_iso "{}" "{}" #{}\n'.format(iso_location, loopback_location, mountpoint)
                else:
                    custom_line = 'amorce_iso "{}" #{}\n'.format(iso_location, mountpoint)
                temporary = True
            custom_content.append(custom_line)
        # Création du Custom
        custom.write_lines(custom_content)
        # Mise à jour de l'environement de GRUB
        if temporary:
            question = QMessageBox(self)
            question.setText("Votre configuration contient une entrée temporaire.")
            question.setInformativeText("Voulez-vous l'activer ?") 
            question.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            question.setDefaultButton(QMessageBox.Yes)
            answer = question.exec_()
            if answer == QMessageBox.Yes:
                subprocess.call(["grub-editenv", self.grubDir / "grubenv", "set", "amorceiso=true"])
        # Affichage d'un message de confirmation
        msg = "Vos modifications ont bien été prises en compte."
        info = QMessageBox(self)
        info.setWindowTitle("GrubEnhancer")
        info.setText(msg)
        info.exec_()
    
    def loadGrubDir(self):
        
        self.customEditor.setGrubRep(self.grubDir)
        
        forbiddenFilesystem = ("btrfs", "cpiofs", "newc","odc",
                               "romfs", "squash4", "tarfs", "zfs")
        forbiddenDeviceName = ("/dev/mapper", "/dev/dm", "/dev/md")
        
        filesystem = subprocess.check_output(["grub-probe", "--target=fs", self.grubDir]).decode().split()[0]
        disque = subprocess.check_output(["grub-probe", "--target=disk", self.grubDir]).decode().split()[0]
        
        if filesystem in forbiddenFilesystem or disque.startswith(forbiddenDeviceName):
            self.options.disablePerm()
        else:
            self.options.enablePerm()
    
    @pyqtSlot()
    def chooseAnotherGrubDir(self):
        choices = GrubList(parent=self)
        grubDir = choices.selectGrubRep()
        if grubDir:
            self.grubDir = path(grubDir)
            self.loadGrubDir()