/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to dulwich/dulwich/repo.py

Unmark as deprecated.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
import os
21
21
 
22
22
from commit import Commit
23
 
from errors import (
24
 
        MissingCommitError, 
25
 
        NotBlobError, 
26
 
        NotCommitError, 
27
 
        NotGitRepository,
28
 
        NotTreeError, 
29
 
        )
30
 
from object_store import ObjectStore
31
 
from objects import (
32
 
        ShaFile,
33
 
        Commit,
34
 
        Tree,
35
 
        Blob,
36
 
        )
 
23
from errors import MissingCommitError
 
24
from objects import (ShaFile,
 
25
                     Commit,
 
26
                     Tree,
 
27
                     Blob,
 
28
                     )
 
29
from pack import load_packs
37
30
 
38
31
OBJECTDIR = 'objects'
 
32
PACKDIR = 'pack'
39
33
SYMREF = 'ref: '
40
34
 
41
35
 
51
45
  ref_locs = ['', 'refs', 'refs/tags', 'refs/heads', 'refs/remotes']
52
46
 
53
47
  def __init__(self, root):
54
 
    if os.path.isdir(os.path.join(root, ".git", "objects")):
 
48
    controldir = os.path.join(root, ".git")
 
49
    if os.path.exists(os.path.join(controldir, "objects")):
55
50
      self.bare = False
56
 
      self._controldir = os.path.join(root, ".git")
57
 
    elif os.path.isdir(os.path.join(root, "objects")):
 
51
      self._basedir = controldir
 
52
    else:
58
53
      self.bare = True
59
 
      self._controldir = root
60
 
    else:
61
 
      raise NotGitRepository(root)
62
 
    self.path = root
 
54
      self._basedir = root
 
55
    self.path = controldir
63
56
    self.tags = [Tag(name, ref) for name, ref in self.get_tags().items()]
64
 
    self._object_store = None
65
 
 
66
 
  def controldir(self):
67
 
    return self._controldir
68
 
 
69
 
  def find_missing_objects(self, determine_wants, graph_walker, progress):
70
 
    """Fetch the missing objects required for a set of revisions.
71
 
 
72
 
    :param determine_wants: Function that takes a dictionary with heads 
73
 
        and returns the list of heads to fetch.
74
 
    :param graph_walker: Object that can iterate over the list of revisions 
75
 
        to fetch and has an "ack" method that will be called to acknowledge 
76
 
        that a revision is present.
77
 
    :param progress: Simple progress function that will be called with 
78
 
        updated progress strings.
79
 
    """
80
 
    wants = determine_wants(self.get_refs())
81
 
    commits_to_send = set(wants)
82
 
    sha_done = set()
83
 
    ref = graph_walker.next()
84
 
    while ref:
85
 
        sha_done.add(ref)
86
 
        if ref in self.object_store:
87
 
            graph_walker.ack(ref)
88
 
        ref = graph_walker.next()
89
 
    while commits_to_send:
90
 
        sha = commits_to_send.pop()
91
 
        if sha in sha_done:
92
 
            continue
93
 
 
94
 
        c = self.commit(sha)
95
 
        assert isinstance(c, Commit)
96
 
        sha_done.add(sha)
97
 
 
98
 
        commits_to_send.update([p for p in c.parents if not p in sha_done])
99
 
 
100
 
        def parse_tree(tree, sha_done):
101
 
            for mode, name, x in tree.entries():
102
 
                if not x in sha_done:
103
 
                    try:
104
 
                        t = self.tree(x)
105
 
                        sha_done.add(x)
106
 
                        parse_tree(t, sha_done)
107
 
                    except:
108
 
                        sha_done.add(x)
109
 
 
110
 
        treesha = c.tree
111
 
        if treesha not in sha_done:
112
 
            t = self.tree(treesha)
113
 
            sha_done.add(treesha)
114
 
            parse_tree(t, sha_done)
115
 
 
116
 
        progress("counting objects: %d\r" % len(sha_done))
117
 
    return sha_done
118
 
 
119
 
  def fetch_objects(self, determine_wants, graph_walker, progress):
120
 
    """Fetch the missing objects required for a set of revisions.
121
 
 
122
 
    :param determine_wants: Function that takes a dictionary with heads 
123
 
        and returns the list of heads to fetch.
124
 
    :param graph_walker: Object that can iterate over the list of revisions 
125
 
        to fetch and has an "ack" method that will be called to acknowledge 
126
 
        that a revision is present.
127
 
    :param progress: Simple progress function that will be called with 
128
 
        updated progress strings.
129
 
    """
130
 
    shas = self.find_missing_objects(determine_wants, graph_walker, progress)
131
 
    for sha in shas:
132
 
        yield self.get_object(sha)
 
57
    self._packs = None
 
58
 
 
59
  def basedir(self):
 
60
    return self._basedir
133
61
 
134
62
  def object_dir(self):
135
 
    return os.path.join(self.controldir(), OBJECTDIR)
136
 
 
137
 
  @property
138
 
  def object_store(self):
139
 
    if self._object_store is None:
140
 
        self._object_store = ObjectStore(self.object_dir())
141
 
    return self._object_store
 
63
    return os.path.join(self.basedir(), OBJECTDIR)
142
64
 
143
65
  def pack_dir(self):
144
66
    return os.path.join(self.object_dir(), PACKDIR)
145
67
 
 
68
  def _get_packs(self):
 
69
    if self._packs is None:
 
70
        self._packs = list(load_packs(self.pack_dir()))
 
71
    return self._packs
 
72
 
146
73
  def _get_ref(self, file):
147
74
    f = open(file, 'rb')
148
75
    try:
152
79
        if ref[-1] == '\n':
153
80
          ref = ref[:-1]
154
81
        return self.ref(ref)
155
 
      assert len(contents) == 41, 'Invalid ref in %s' % file
 
82
      assert len(contents) == 41, 'Invalid ref'
156
83
      return contents[:-1]
157
84
    finally:
158
85
      f.close()
159
86
 
160
87
  def ref(self, name):
161
88
    for dir in self.ref_locs:
162
 
      file = os.path.join(self.controldir(), dir, name)
 
89
      file = os.path.join(self.basedir(), dir, name)
163
90
      if os.path.exists(file):
164
91
        return self._get_ref(file)
165
92
 
166
 
  def get_refs(self):
167
 
    ret = {}
168
 
    if self.head():
169
 
        ret['HEAD'] = self.head()
170
 
    for dir in ["refs/heads", "refs/tags"]:
171
 
        for name in os.listdir(os.path.join(self.controldir(), dir)):
172
 
          path = os.path.join(self.controldir(), dir, name)
173
 
          if os.path.isfile(path):
174
 
            ret["/".join([dir, name])] = self._get_ref(path)
175
 
    return ret
176
 
 
177
 
  def set_ref(self, name, value):
178
 
    file = os.path.join(self.controldir(), name)
179
 
    open(file, 'w').write(value+"\n")
180
 
 
181
 
  def remove_ref(self, name):
182
 
    file = os.path.join(self.controldir(), name)
183
 
    if os.path.exists(file):
184
 
      os.remove(file)
185
 
      return
186
 
 
187
93
  def get_tags(self):
188
94
    ret = {}
189
 
    for root, dirs, files in os.walk(os.path.join(self.controldir(), 'refs', 'tags')):
 
95
    for root, dirs, files in os.walk(os.path.join(self.basedir(), 'refs', 'tags')):
190
96
      for name in files:
191
97
        ret[name] = self._get_ref(os.path.join(root, name))
192
98
    return ret
193
99
 
194
100
  def heads(self):
195
101
    ret = {}
196
 
    for root, dirs, files in os.walk(os.path.join(self.controldir(), 'refs', 'heads')):
 
102
    for root, dirs, files in os.walk(os.path.join(self.basedir(), 'refs', 'heads')):
197
103
      for name in files:
198
104
        ret[name] = self._get_ref(os.path.join(root, name))
199
105
    return ret
202
108
    return self.ref('HEAD')
203
109
 
204
110
  def _get_object(self, sha, cls):
205
 
    assert len(sha) in (20, 40)
206
 
    ret = self.get_object(sha)
207
 
    if ret._type != cls._type:
208
 
        if cls is Commit:
209
 
            raise NotCommitError(ret)
210
 
        elif cls is Blob:
211
 
            raise NotBlobError(ret)
212
 
        elif cls is Tree:
213
 
            raise NotTreeError(ret)
214
 
        else:
215
 
            raise Exception("Type invalid: %r != %r" % (ret._type, cls._type))
216
 
    return ret
 
111
    assert len(sha) == 40, "Incorrect length sha: %s" % str(sha)
 
112
    dir = sha[:2]
 
113
    file = sha[2:]
 
114
    # Check from object dir
 
115
    path = os.path.join(self.object_dir(), dir, file)
 
116
    if os.path.exists(path):
 
117
      return cls.from_file(path)
 
118
    # Check from packs
 
119
    for pack in self._get_packs():
 
120
        if sha in pack:
 
121
            return pack[sha]
 
122
    # Should this raise instead?
 
123
    return None
217
124
 
218
125
  def get_object(self, sha):
219
 
    return self.object_store[sha]
220
 
 
221
 
  def get_parents(self, sha):
222
 
    return self.commit(sha).parents
 
126
    return self._get_object(sha, ShaFile)
223
127
 
224
128
  def commit(self, sha):
225
129
    return self._get_object(sha, Commit)
226
130
 
227
 
  def tree(self, sha):
 
131
  def get_tree(self, sha):
228
132
    return self._get_object(sha, Tree)
229
133
 
230
134
  def get_blob(self, sha):
247
151
    history = []
248
152
    while pending_commits != []:
249
153
      head = pending_commits.pop(0)
250
 
      try:
251
 
          commit = self.commit(head)
252
 
      except KeyError:
 
154
      commit = self.commit(head)
 
155
      if commit is None:
253
156
        raise MissingCommitError(head)
254
157
      if commit in history:
255
158
        continue
264
167
    history.reverse()
265
168
    return history
266
169
 
267
 
  def __repr__(self):
268
 
      return "<Repo at %r>" % self.path
269
 
 
270
 
  @classmethod
271
 
  def init(cls, path, mkdir=True):
272
 
      controldir = os.path.join(path, ".git")
273
 
      os.mkdir(controldir)
274
 
      cls.init_bare(controldir)
275
 
 
276
170
  @classmethod
277
171
  def init_bare(cls, path, mkdir=True):
278
172
      for d in [["objects"], 
291
185
 
292
186
  create = init_bare
293
187
 
294
 
 
295