summaryrefslogtreecommitdiffstats
path: root/fit.py
blob: ce5b3d773ae9ae2242ce865bd8adfd87e7f8aff1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import os, time
import collections

from pygit2 import Repository, Signature
from binascii import b2a_hex


class Fit:
  def __init__(self, path):
    self.repo = Repository(path)

  def _insert_node(self, node_oid, path, root_oid):
    filename = os.path.basename(path)

    if root_oid:
      root = self.repo.TreeBuilder(root_oid)
      current_node = self.repo[root_oid]
    else:
      root = self.repo.TreeBuilder()
      current_node = root.write()

    entries = path.split('/')[:-1]
    entries.reverse()

    # search for existing nodes in path
    tree_path = [('/', root)]
    while len(entries) > 0:
      if entries[-1] not in current_node:
        break

      entry = entries.pop()
      current_node = self.repo[current_node[entry].oid]
      tree_path.append((
        entry, self.repo.TreeBuilder(current_node.oid)
      ))

    # create node
    if len(entries) > 0:
      tmp = self.repo.TreeBuilder()
    elif len(tree_path) > 0:
      tmp = tree_path[-1][1]
    else:
      tmp = root

    tmp.insert(filename, node_oid, 0100644)
    current = tmp.write()

    # create new nodes bottom-up for our node
    size = len(entries)
    for i, entry in enumerate(entries):
      if i < (size - 1):
        tmp = self.repo.TreeBuilder()
        tmp.insert(entry, current, 040000)
        current = tmp.write()
      else:
        tree_path.append((entry, None))

    # connect existing nodes with created nodes
    pre = tree_path.pop()[0]
    tree_path.reverse()
    for name, builder in tree_path:
      builder.insert(pre, current, 040000)
      current = builder.write()
      pre = name 

    return current


  def _get_last_commit(self):
      head = self.repo.lookup_reference('HEAD').resolve()
      return self.repo[head.oid]


  def add_file(self, data, git_path, tags):
    try:
      commit = self._get_last_commit()
      parents = [commit.oid]
      root = commit.tree.oid

    except:
      parents = []
      root = None


    blob_oid = self.repo.create_blob(data)
    root = self._insert_node(blob_oid, git_path, root)
    filename = os.path.basename(git_path)
    for tag in tags:
      name = 'tags/%s/%s' % (tag, filename)
      root = self._insert_node(blob_oid, name, root)

    author = committer = Signature('Fit', 'Fit@fit.de',  int(time.time()), 120)

    commit = self.repo.create_commit(
      'HEAD',
      author,
      committer,
      'added %s' % git_path,
      root,
      parents
    )

    return b2a_hex(blob_oid).decode('ascii')


  def get_all_files(self):
    try:
      commit = self._get_last_commit()
      files = commit.tree['files'].to_object()
      return ((x.name, x.hex) for x in files)
    except:
      return []


  def get_file(self, oid):
    return self.repo[oid].data


  def get_all_tags(self):
    try:
      commit = self._get_last_commit()
      tags = commit.tree['tags'].to_object()
      return ((x.name, x.hex) for x in tags)
    except:
      return []


  def get_files_for_tags(self, tags):
    try:
      commit = self._get_last_commit()
      root = commit.tree['tags'].to_object()

      def get_obj(x):
        try:
          return root[x.encode('ascii')].to_object()
        except KeyError:
          return []

      entries = [get_obj(x) for x in tags]

      def merge(list_to_merge):
        for sublist in list_to_merge:
          for elem in sublist:
            yield elem

      # return only entries which have all tags
      search = collections.Counter([(x.name, x.hex) for x in merge(entries)])
      return [i for i in search if search[i]>=len(tags)]

    except:
      return []


  def get_tags_for_file(self, oid):
    tags = []
    for name, tag_oid in self.get_all_tags():
      for entry in self.repo[tag_oid]:
        if b2a_hex(entry.oid).decode('ascii') == oid:
          tags.append(name)

    return tags


#fit = Fit('tmp/fit')
#fit.add_file('main.c', 'files/main.c', ['alp2', '2007'])
#
#print("All files")
#for name, oid in fit.get_all_files():
#  tags = ','.join(map(lambda x: x[0], fit.get_file_with_tags(oid)))
#  print("* %s (%s)" % (name, tags))
#  #print(fit.get_file(oid) + "\n")
#
#print("\nAll tags")
#for name, oid in fit.get_all_tags():
#  files = ','.join(map(lambda x: x[0], fit.get_files_for_tags([name])))
#  print("* %s (%s)" % (name, files))