summaryrefslogtreecommitdiffstats
path: root/app/fit.py
diff options
context:
space:
mode:
Diffstat (limited to 'app/fit.py')
-rw-r--r--app/fit.py136
1 files changed, 136 insertions, 0 deletions
diff --git a/app/fit.py b/app/fit.py
new file mode 100644
index 0000000..6fbc13f
--- /dev/null
+++ b/app/fit.py
@@ -0,0 +1,136 @@
+#!/usr/bin/python2
+# -*- coding: utf-8 -*-
+
+import os, time
+import collections
+
+from pygit2 import init_repository, Signature, GIT_FILEMODE_TREE, GIT_FILEMODE_BLOB
+from binascii import b2a_hex
+
+
+class Fit:
+ def __init__(self, path):
+ self.repo = init_repository(path, True)
+
+
+ def get_file(self, oid):
+ """ Returns the actual data of a git object """
+ return self.repo[oid].data
+
+
+ def get_modules(self):
+ """ returns a list of all modules """
+ return [x[0] for x in self._list()]
+
+
+ def get_module(self, module):
+ """ gets all entries for a module grouped by years """
+ years = self._list(module)
+ return [(year[0], self._list(os.path.join(module, year[0]))) for year in years]
+
+ def add_file(self, data, path):
+ """ Inserts the given file in the git tree and commits the changes """
+ try:
+ commit = self.repo.head.get_object()
+ parents = commit.parents
+ root = commit.tree.id
+
+ except:
+ parents = []
+ root = None
+
+
+ blob_oid = self.repo.create_blob(data)
+ tree = self._insert_node(blob_oid, path, root)
+ author = committer = Signature('Fit', 'Fit@fit.de', int(time.time()), 120)
+
+ commit = self.repo.create_commit(
+ 'HEAD',
+ author,
+ committer,
+ 'added %s' % path,
+ tree,
+ [p.id for p in parents]
+ )
+
+ # save the actual head sha for dump git http protocol
+ # similiar to `git update-server-info`
+ info_refs_path = os.path.join(self.repo.path, 'info', 'refs')
+ with open(info_refs_path, 'w') as f:
+ f.write('%s\trefs/heads/master\n' % b2a_hex(str(commit)).decode('ascii'))
+
+ return b2a_hex(str(blob_oid)).decode('ascii')
+
+
+ def _insert_node(self, node_oid, path, root_oid):
+ """ Inserts a new Node in a Git Tree graph """
+ if root_oid:
+ root = self.repo.TreeBuilder(root_oid)
+ current_node = self.repo[root_oid]
+ else:
+ root = self.repo.TreeBuilder()
+ current_node = self.repo[root.write()]
+
+ # entire path
+ dir_path = path.split(os.sep)[:-1]
+
+ # search for existing nodes in path
+ existing_builders = [(os.sep, root)]
+ for dir_entry in dir_path:
+ try:
+ new_oid = current_node[dir_entry].oid
+ current_node = self.repo[new_oid]
+
+ existing_builders.append((
+ dir_entry, self.repo.TreeBuilder(current_node)
+ ))
+ except KeyError:
+ break
+
+ # directories to create
+ new_path = dir_path[len(existing_builders)-1:]
+
+ # inserts blob object
+ filename = os.path.basename(path)
+
+ if len(new_path) > 0:
+ builder = self.repo.TreeBuilder()
+ pre = filename
+ else:
+ last_dir = existing_builders.pop()
+ builder = last_dir[1]
+ pre = last_dir[0]
+
+ builder.insert(filename, node_oid, GIT_FILEMODE_BLOB)
+ current_tree_oid = builder.write()
+
+ # create new nodes bottom-up for our node
+ if len(new_path) > 0:
+ pre = new_path.pop(0)
+ for entry in reversed(new_path):
+ builder = self.repo.TreeBuilder()
+ builder.insert(entry, current_tree_oid, GIT_FILEMODE_TREE)
+ current_tree_oid = builder.write()
+
+ # connect existing nodes with created nodes
+ for name, builder in reversed(existing_builders):
+ builder.insert(pre, current_tree_oid, GIT_FILEMODE_TREE)
+ current_tree_oid = builder.write()
+ pre = name
+
+ return current_tree_oid
+
+
+ def _list(self, path=None):
+ """ Lists all entries for a given path """
+ try:
+ tree = self.repo.head.get_object().tree
+
+ if path:
+ for p in path.split('/'):
+ tree = self.repo[tree[p].id]
+
+ return [(x.name, x.hex) for x in tree]
+
+ except:
+ return []