/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/repo.py

  • Committer: Jelmer Vernooij
  • Date: 2008-12-08 23:24:15 UTC
  • mto: (0.215.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@samba.org-20081208232415-odeovndmt9vvsfik
remove silly build-inplace target.

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
                     )
37
29
 
38
 
OBJECTDIR = 'objects'
39
 
SYMREF = 'ref: '
 
30
objectdir = 'objects'
 
31
symref = 'ref: '
40
32
 
41
33
 
42
34
class Tag(object):
43
35
 
44
36
    def __init__(self, name, ref):
45
37
        self.name = name
46
 
        self.ref = ref
 
38
        self.commit = Commit(ref)
47
39
 
48
40
 
49
41
class Repo(object):
51
43
  ref_locs = ['', 'refs', 'refs/tags', 'refs/heads', 'refs/remotes']
52
44
 
53
45
  def __init__(self, root):
54
 
    if os.path.isdir(os.path.join(root, ".git", "objects")):
 
46
    controldir = os.path.join(root, ".git")
 
47
    if os.path.exists(os.path.join(controldir, "objects")):
55
48
      self.bare = False
56
 
      self._controldir = os.path.join(root, ".git")
57
 
    elif os.path.isdir(os.path.join(root, "objects")):
 
49
      self._basedir = controldir
 
50
    else:
58
51
      self.bare = True
59
 
      self._controldir = root
60
 
    else:
61
 
      raise NotGitRepository(root)
62
 
    self.path = root
 
52
      self._basedir = root
 
53
    self.path = controldir
63
54
    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)
 
55
 
 
56
  def basedir(self):
 
57
    return self._basedir
133
58
 
134
59
  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
142
 
 
143
 
  def pack_dir(self):
144
 
    return os.path.join(self.object_dir(), PACKDIR)
 
60
    return os.path.join(self.basedir(), objectdir)
145
61
 
146
62
  def _get_ref(self, file):
147
63
    f = open(file, 'rb')
148
64
    try:
149
65
      contents = f.read()
150
 
      if contents.startswith(SYMREF):
151
 
        ref = contents[len(SYMREF):]
 
66
      if contents.startswith(symref):
 
67
        ref = contents[len(symref):]
152
68
        if ref[-1] == '\n':
153
69
          ref = ref[:-1]
154
70
        return self.ref(ref)
155
 
      assert len(contents) == 41, 'Invalid ref in %s' % file
 
71
      assert len(contents) == 41, 'Invalid ref'
156
72
      return contents[:-1]
157
73
    finally:
158
74
      f.close()
159
75
 
160
76
  def ref(self, name):
161
77
    for dir in self.ref_locs:
162
 
      file = os.path.join(self.controldir(), dir, name)
 
78
      file = os.path.join(self.basedir(), dir, name)
163
79
      if os.path.exists(file):
164
80
        return self._get_ref(file)
165
81
 
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
82
  def get_tags(self):
188
83
    ret = {}
189
 
    for root, dirs, files in os.walk(os.path.join(self.controldir(), 'refs', 'tags')):
190
 
      for name in files:
191
 
        ret[name] = self._get_ref(os.path.join(root, name))
 
84
    for name in os.listdir(os.path.join(self.basedir(), 'refs', 'tags')):
 
85
      ret[name] = self._get_ref(os.path.join(self.basedir(), 'refs', 'tags', name))
192
86
    return ret
193
87
 
194
88
  def heads(self):
195
89
    ret = {}
196
 
    for root, dirs, files in os.walk(os.path.join(self.controldir(), 'refs', 'heads')):
197
 
      for name in files:
198
 
        ret[name] = self._get_ref(os.path.join(root, name))
 
90
    for name in os.listdir(os.path.join(self.basedir(), 'refs', 'heads')):
 
91
      ret[name] = self._get_ref(os.path.join(self.basedir(), 'refs', 'heads', name))
199
92
    return ret
200
93
 
201
94
  def head(self):
202
95
    return self.ref('HEAD')
203
96
 
204
97
  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
 
98
    assert len(sha) == 40, "Incorrect length sha: %s" % str(sha)
 
99
    dir = sha[:2]
 
100
    file = sha[2:]
 
101
    path = os.path.join(self.object_dir(), dir, file)
 
102
    if not os.path.exists(path):
 
103
      # Should this raise instead?
 
104
      return None
 
105
    return cls.from_file(path)
217
106
 
218
107
  def get_object(self, sha):
219
 
    return self.object_store[sha]
220
 
 
221
 
  def get_parents(self, sha):
222
 
    return self.commit(sha).parents
 
108
    return self._get_object(sha, ShaFile)
223
109
 
224
110
  def commit(self, sha):
225
111
    return self._get_object(sha, Commit)
226
112
 
227
 
  def tree(self, sha):
 
113
  def get_tree(self, sha):
228
114
    return self._get_object(sha, Tree)
229
115
 
230
116
  def get_blob(self, sha):
247
133
    history = []
248
134
    while pending_commits != []:
249
135
      head = pending_commits.pop(0)
250
 
      try:
251
 
          commit = self.commit(head)
252
 
      except KeyError:
 
136
      commit = self.commit(head)
 
137
      if commit is None:
253
138
        raise MissingCommitError(head)
254
139
      if commit in history:
255
140
        continue
256
141
      i = 0
257
142
      for known_commit in history:
258
 
        if known_commit.commit_time > commit.commit_time:
 
143
        if known_commit.commit_time() > commit.commit_time():
259
144
          break
260
145
        i += 1
261
146
      history.insert(i, commit)
262
 
      parents = commit.parents
 
147
      parents = commit.parents()
263
148
      pending_commits += parents
264
149
    history.reverse()
265
150
    return history
266
151
 
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
152
  @classmethod
277
153
  def init_bare(cls, path, mkdir=True):
278
154
      for d in [["objects"], 
291
167
 
292
168
  create = init_bare
293
169
 
294
 
 
295