diff options
Diffstat (limited to 'app/fit.py')
-rw-r--r-- | app/fit.py | 136 |
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 [] |