Created
January 24, 2012 19:56
-
-
Save niklasfi/1672201 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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