Skip to content

Instantly share code, notes, and snippets.

@niklasfi
Created January 24, 2012 19:56
Show Gist options
  • Save niklasfi/1672201 to your computer and use it in GitHub Desktop.
Save niklasfi/1672201 to your computer and use it in GitHub Desktop.
#!/usr/bin/python
# -*- coding: utf-8 -*-
from PyQt4 import QtGui as gui
from PyQt4 import QtCore as core
import sys
import os
import argparse
import subprocess
import select
import re
from threading import Timer, Thread
import Queue
from math import ceil
logto = "/var/lib/pyqt-copier/echolog"
def logger(whereto):
if whereto:
f = open(whereto,'a')
return f.write
else:
return sys.stdout.write
log = logger(logto)
class NiceQ(Queue.Queue):
def __init__(self, fd,*args, **kwargs):
Queue.Queue.__init__(self)
self.fd = fd
self.t = Thread(target=self.enque)
self.t.deamon = True
self.t.start()
def enque(self):
for line in iter(self.fd.readline, ''):
self.put(line)
self.fd.close()
class DeviceWorker(gui.QWidget):
def __init__(self,args):
super(DeviceWorker, self).__init__()
self.src = args.source
self.dest = args.destination
self.bs = args.bs
self.progress = 0
if args.size:
self.size = args.size
if self.size == 0:
log( "I cannot write 0 bytes!\n" )
sys.exit(2)
else:
self.size = os.path.getsize(self.src)
if args.dry:
log( """running in dry mode
if this was real, i would copy
print "%s to %s" % (self.src, self.dest)
self.src = '/dev/zero""")
self.dest = '/dev/null'
log( "size: %s\n" % (self.size / self.bs))
self.initUI()
if gui.QMessageBox.question(self, self.dest ,u"%s unwiederruflich überschreiben?" % self.dest,"Ja","Nein",defaultButtonNumber=1) == 1:
log( u"durch Benutzer abgebrochen\n" )
sys.exit(1)
self.startcopy()
def close(self,e):
if not self.dd == None:
if gui.QMessageBox.warning(self,"Abbruch","Kopiervorgang abbrechen?","Ja","Nein",defaultButtonNumber=1) == 1:
e.ignore()
self.hide()
self.dd.terminate()
log( "now gracefully exiting\n" )
sys.exit(0)
def initUI(self):
self.resize(400,0)
self.pbar = gui.QProgressBar()
if self.size:
self.pbar.setRange(0,100)
else:
self.pbar.setRange(0,0)
self.vboxl = gui.QVBoxLayout()
self.lbl = gui.QLabel()
self.lbl.setText(u"initializing…")
self.lbl.setAlignment(core.Qt.AlignHCenter | core.Qt.AlignTop)
self.vboxl.addWidget(self.lbl)
self.vboxl.addWidget(self.pbar)
self.setLayout(self.vboxl)
self.setWindowTitle(u"%s -> %s" % (self.src, self.dest))
self.setWindowIcon(gui.QIcon('icon.png'))
self.closeEvent = self.close
self.show()
def timerEvent(self,e):
if not self.dd.poll() == None:
return self.done()
self.dd.send_signal(10) #USR1
while True:
try:
str = self.q.get_nowait()
match = re.match("(?P<progress>[0-9]+) Bytes",str)
if match:
self.pbar.setTextVisible(True)
self.lbl.setText( str)
self.progress = int(match.group('progress'))
if self.size > 0:
self.pbar.setValue(self.progress*100/self.size)
except Queue.Empty:
break
def startcopy(self):
call = ['dd','bs=%s' % self.bs, 'if=%s' % self.src, 'of=%s' % self.dest];
if self.size != 0:
call.append('count=%s' % int(ceil(self.size / self.bs)))
log( "calling %s\n" % " ".join(call) )
self.dd = subprocess.Popen( call, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
log( "started dd subprocess with pid %s\n" % self.dd.pid )
self.timer = core.QTimer()
self.timer.setInterval(100)
self.timer.timerEvent = self.timerEvent
self.timer.start()
self.q = NiceQ(self.dd.stderr)
def done(self):
self.timer.stop()
self.pbar.setRange(0,100)
self.pbar.setValue(100)
log( "dd gave return code %s\n" % self.dd.poll() )
self.dd = None
log ("done\n")
def main():
parser = argparse.ArgumentParser(description='fancy gui for copying stuff using dd')
parser.add_argument('source', action="store", help="the source for dd to use")
parser.add_argument('destination', action="store", help="the target, where dd should shove the data")
parser.add_argument('-d', '--dry-run', action="store_true", dest="dry", help="do not do any actual file io", default=False)
parser.add_argument('-s', '--filesize', action="store", dest="size", help="number of bytes to be copied", type=int)
parser.add_argument('-b', '--buffersize', action="store", dest="bs", help="buffer size to be used",default=1024*1024,type=int)
args = parser.parse_args()
newpid = os.fork()
if newpid != 0:
sys.exit(0)
log( "forked \n")
app = gui.QApplication([])
log( "app created\n")
w = DeviceWorker(args)
log( "window created\n")
sys.exit(app.exec_())
if __name__ == '__main__':
main()
SUBSYSTEM=="block"
DRIVERS=="usb-storage" \
KERNEL=="sd[a-z]" \
ACTION=="add" \
PROGRAM="/var/lib/pyqt-copier/namer.py %p" \
SYMLINK+="%c" \
RUN+="/var/lib/pyqt-copier/qtcopier.py -d /dev/zero /dev/pyqt-copier/%c" \
RUN+="/var/lib/pyqt-copier/log.sh %c"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment