summaryrefslogtreecommitdiffstats
path: root/src/git_tftpd/writer.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/git_tftpd/writer.py')
-rw-r--r--src/git_tftpd/writer.py66
1 files changed, 66 insertions, 0 deletions
diff --git a/src/git_tftpd/writer.py b/src/git_tftpd/writer.py
new file mode 100644
index 0000000..bee731c
--- /dev/null
+++ b/src/git_tftpd/writer.py
@@ -0,0 +1,66 @@
+import os
+import shutil
+import socket
+import tempfile
+
+from .git import GitRepo
+
+from tftp.backend import IWriter
+from twisted.python import log
+from zope import interface
+
+
+class GitWriter(object):
+ interface.implements(IWriter)
+
+ def __init__(self, file_path, repo, remote):
+ file_dir = file_path.parent()
+ if not file_dir.exists():
+ file_dir.makedirs()
+
+ self.file_path = file_path
+ self.temp_destination = tempfile.TemporaryFile()
+ self.repo = os.path.abspath(repo)
+ self.remote = remote
+ self.state = 'active'
+
+ def _get_hostname(self, remote):
+ try:
+ flags = socket.NI_DGRAM | socket.NI_NOFQDN | socket.NI_NAMEREQD
+ (host, _) = socket.getnameinfo(remote, flags)
+ except:
+ (host, _) = remote
+ return host
+
+ def _do_git_commit(self):
+ git_repo = GitRepo(self.repo)
+ git_repo.stage([self.file_path.path])
+
+ if not git_repo.has_changed():
+ return
+
+ msg = 'Automatic commit after tftp upload'
+ if self.remote is not None:
+ msg += ' from %s' % self._get_hostname(self.remote)
+ committer = 'Backup Server <backup@spline.inf.fu-berlin.de>'
+ git_repo.commit(msg, committer)
+ git_repo.push('origin')
+
+ def write(self, data):
+ self.temp_destination.write(data)
+
+ def finish(self):
+ if self.state not in ('finished', 'cancelled'):
+ self.destination_file = self.file_path.open('w')
+ self.temp_destination.seek(0)
+ shutil.copyfileobj(self.temp_destination, self.destination_file)
+ self.temp_destination.close()
+ self.destination_file.close()
+
+ self._do_git_commit()
+ self.state = 'finished'
+
+ def cancel(self):
+ if self.state not in ('finished', 'cancelled'):
+ self.temp_destination.close()
+ self.state = 'cancelled'