Игорь Пашев -

Sep. 21st, 2009

10:17 pm

Previous Entry Add to Memories Tell A Friend Next Entry

После обновления Слаки с директории /etc
остаётся несколько файлов типа rc.inet1.new,
которые по идее должны заменить старые файлы (типа rc.inet1).

Я обычно это делал руками: diff -u rc.inet1 rc.inet1.new,
а затем принимал решение о замене.
мне это надоело, и я написал программу на Питоне,
которая это автоматизирует.
Программа графическая, использует Qt4, pygments.


http://picasaweb.google.ru/lh/photo/EVmsIvYlCcb-ZmFgkTSdNQ?feat=directlink

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import sys
import os
import stat
import glob
import difflib
import string
from PyQt4 import QtGui, QtCore
from pygments import highlight
from pygments.lexers import DiffLexer
from pygments.formatters import HtmlFormatter

editor = 'gvim -f'

# find all *.new files in /etc
def findnew (top = '/etc', depthfirst = True):
    os.chdir(top)
    names = glob.glob('*.new')
    if not depthfirst:
        yield top, names
    for name in names:
        try:
            st = os.lstat(os.path.join(top, name))
        except os.error:
            continue
        if stat.S_ISDIR(st.st_mode):
            for (newtop, children) in findnew (os.path.join(top, name), depthfirst):
                yield newtop, children
    if depthfirst:
        yield top, names


class MainWindow(QtGui.QWidget):
    newlist = None # QListWidget
    diff    = None # QTextEdit
    edit    = None # QPushButton
    accept  = None # QPushButton
    reject  = None # QPushButton

    newfile = None # /etc/file.new
    oldfile = None # /etc/file

    def enable_buttons(self):
        n = self.newlist.count()
        self.edit.setEnabled(n > 0)
        self.accept.setEnabled(n > 0)
        self.reject.setEnabled(n > 0)


    @QtCore.pyqtSlot()
    def on_accept(self):
        os.rename(self.newfile, self.oldfile)
        self.newlist.takeItem(self.newlist.currentRow())
        self.enable_buttons()

    @QtCore.pyqtSlot()
    def on_reject(self):
        os.remove(self.newfile)
        self.newlist.takeItem(self.newlist.currentRow())
        self.enable_buttons()

    @QtCore.pyqtSlot()
    def on_edit(self):
        self.accept.setEnabled(False)
        self.newlist.setEnabled(False)
        
        os.system(editor + ' ' + self.oldfile)
        
        self.reloaddiff(self.newfile)
        self.newlist.setEnabled(True)
        self.accept.setEnabled(True)

    @QtCore.pyqtSlot(QtCore.QString)
    def reloaddiff(self, newfile):
        self.diff.clear()
        self.newfile = str(newfile)
        self.oldfile = self.newfile[0:self.newfile.find('.new')]
        if self.newfile:
            tolines      = open(self.newfile, 'U').readlines()
            fromlines    = open(self.oldfile, 'U').readlines()
            difflines    = difflib.unified_diff(fromlines, tolines, self.oldfile, self.newfile)
            difftext = string.join(difflines, '')

            self.edit.setToolTip(editor + ' ' + self.oldfile)
            self.reject.setToolTip('Remove ' + self.newfile)
            self.accept.setToolTip(self.newfile + ' -> ' + self.oldfile)
            self.accept.setEnabled(bool(difftext))

            colored_rtf  = highlight(difftext,
                            DiffLexer(),
                            HtmlFormatter(full=True))
            self.diff.setText(colored_rtf)

    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        mvbox  = QtGui.QVBoxLayout() # main layout
        split  = QtGui.QSplitter(QtCore.Qt.Horizontal, self) # left-right splitter
        
        rpart  = QtGui.QWidget(split) # right side
        lpart  = QtGui.QWidget(split) # left side

        rvbox  = QtGui.QVBoxLayout() # right side layout
        lvbox  = QtGui.QVBoxLayout() # left side layout
        rpart.setLayout(rvbox)
        lpart.setLayout(lvbox)

        self.diff = QtGui.QTextEdit() # to show diff
        self.diff.setReadOnly(True)
      
        self.newlist = QtGui.QListWidget() # to show all *.new files
       # Load all *.new files  
        for (basepath, children) in findnew():
            for child in children:
                self.newlist.addItem(os.path.join(basepath, child))
        
        quit        = QtGui.QPushButton('&Quit', self)
        self.accept = QtGui.QPushButton('&Accept', self)
        self.reject = QtGui.QPushButton('&Reject', self)
        self.edit   = QtGui.QPushButton('&Edit old...', self)

        lvbox.addWidget(self.diff) # diff is on the left side
        buttons = QtGui.QHBoxLayout() # buttons are below it
        lvbox.addLayout(buttons) # buttons layout
        buttons.addWidget(self.accept)
        buttons.addWidget(self.reject)
        buttons.addWidget(self.edit)

        rvbox.addWidget(self.newlist) # file list is on the right side
        rvbox.addWidget(quit) # quit button is below it

        mvbox.addWidget(split) # split is the main widget of main window
        split.addWidget(lpart) # add the left side on the split
        split.addWidget(rpart) # add the right side on the split

        self.resize(640, 480)
        self.setWindowTitle('What\'s new in /etc ?')
        self.setLayout(mvbox)

        self.connect(quit, QtCore.SIGNAL('clicked()'), QtGui.qApp, QtCore.SLOT('quit()'))
        self.connect(self.edit, QtCore.SIGNAL('clicked()'), self, QtCore.SLOT('on_edit()'))
        self.connect(self.accept, QtCore.SIGNAL('clicked()'), self, QtCore.SLOT('on_accept()'))
        self.connect(self.reject, QtCore.SIGNAL('clicked()'), self, QtCore.SLOT('on_reject()'))
        self.connect(self.newlist, QtCore.SIGNAL('currentTextChanged(QString)'),
                             self, QtCore.SLOT('reloaddiff(QString)'))
        
        self.newlist.setCurrentRow(0)
        self.enable_buttons()



app = QtGui.QApplication(sys.argv)
win = MainWindow()
win.show()

sys.exit(app.exec_())

Tags: , , ,
(Оставить комментарий)