После обновления Слаки с директории /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_())