/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-11 07:30:52 UTC
  • mto: (0.215.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@samba.org-20081211073052-lq0ypg5h3vvyzp3j
Change project name to dulwich everywhere, add assertion.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# repo.py -- For dealing wih git repositories.
 
2
# Copyright (C) 2007 James Westby <jw+debian@jameswestby.net>
 
3
# Copyright (C) 2008 Jelmer Vernooij <jelmer@samba.org>
 
4
 
5
# This program is free software; you can redistribute it and/or
 
6
# modify it under the terms of the GNU General Public License
 
7
# as published by the Free Software Foundation; version 2
 
8
# of the License.
 
9
 
10
# This program is distributed in the hope that it will be useful,
 
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
# GNU General Public License for more details.
 
14
 
15
# You should have received a copy of the GNU General Public License
 
16
# along with this program; if not, write to the Free Software
 
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
18
# MA  02110-1301, USA.
 
19
 
 
20
import os
 
21
 
 
22
from commit import Commit
 
23
from errors import MissingCommitError
 
24
from objects import (ShaFile,
 
25
                     Commit,
 
26
                     Tree,
 
27
                     Blob,
 
28
                     )
 
29
 
 
30
objectdir = 'objects'
 
31
symref = 'ref: '
 
32
 
 
33
 
 
34
class Tag(object):
 
35
 
 
36
    def __init__(self, name, ref):
 
37
        self.name = name
 
38
        self.commit = Commit(ref)
 
39
 
 
40
 
 
41
class Repo(object):
 
42
 
 
43
  ref_locs = ['', 'refs', 'refs/tags', 'refs/heads', 'refs/remotes']
 
44
 
 
45
  def __init__(self, root):
 
46
    controldir = os.path.join(root, ".git")
 
47
    if os.path.exists(os.path.join(controldir, "objects")):
 
48
      self.bare = False
 
49
      self._basedir = controldir
 
50
    else:
 
51
      self.bare = True
 
52
      self._basedir = root
 
53
    self.path = controldir
 
54
    self.tags = [Tag(name, ref) for name, ref in self.get_tags().items()]
 
55
 
 
56
  def basedir(self):
 
57
    return self._basedir
 
58
 
 
59
  def object_dir(self):
 
60
    return os.path.join(self.basedir(), objectdir)
 
61
 
 
62
  def _get_ref(self, file):
 
63
    f = open(file, 'rb')
 
64
    try:
 
65
      contents = f.read()
 
66
      if contents.startswith(symref):
 
67
        ref = contents[len(symref):]
 
68
        if ref[-1] == '\n':
 
69
          ref = ref[:-1]
 
70
        return self.ref(ref)
 
71
      assert len(contents) == 41, 'Invalid ref'
 
72
      return contents[:-1]
 
73
    finally:
 
74
      f.close()
 
75
 
 
76
  def ref(self, name):
 
77
    for dir in self.ref_locs:
 
78
      file = os.path.join(self.basedir(), dir, name)
 
79
      if os.path.exists(file):
 
80
        return self._get_ref(file)
 
81
 
 
82
  def get_tags(self):
 
83
    ret = {}
 
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))
 
86
    return ret
 
87
 
 
88
  def heads(self):
 
89
    ret = {}
 
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))
 
92
    return ret
 
93
 
 
94
  def head(self):
 
95
    return self.ref('HEAD')
 
96
 
 
97
  def _get_object(self, sha, cls):
 
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)
 
106
 
 
107
  def get_object(self, sha):
 
108
    return self._get_object(sha, ShaFile)
 
109
 
 
110
  def commit(self, sha):
 
111
    return self._get_object(sha, Commit)
 
112
 
 
113
  def get_tree(self, sha):
 
114
    return self._get_object(sha, Tree)
 
115
 
 
116
  def get_blob(self, sha):
 
117
    return self._get_object(sha, Blob)
 
118
 
 
119
  def revision_history(self, head):
 
120
    """Returns a list of the commits reachable from head.
 
121
 
 
122
    Returns a list of commit objects. the first of which will be the commit
 
123
    of head, then following theat will be the parents.
 
124
 
 
125
    Raises NotCommitError if any no commits are referenced, including if the
 
126
    head parameter isn't the sha of a commit.
 
127
 
 
128
    XXX: work out how to handle merges.
 
129
    """
 
130
    # We build the list backwards, as parents are more likely to be older
 
131
    # than children
 
132
    pending_commits = [head]
 
133
    history = []
 
134
    while pending_commits != []:
 
135
      head = pending_commits.pop(0)
 
136
      commit = self.commit(head)
 
137
      if commit is None:
 
138
        raise MissingCommitError(head)
 
139
      if commit in history:
 
140
        continue
 
141
      i = 0
 
142
      for known_commit in history:
 
143
        if known_commit.commit_time() > commit.commit_time():
 
144
          break
 
145
        i += 1
 
146
      history.insert(i, commit)
 
147
      parents = commit.parents()
 
148
      pending_commits += parents
 
149
    history.reverse()
 
150
    return history
 
151
 
 
152
  @classmethod
 
153
  def init_bare(cls, path, mkdir=True):
 
154
      for d in [["objects"], 
 
155
                ["objects", "info"], 
 
156
                ["objects", "pack"],
 
157
                ["branches"],
 
158
                ["refs"],
 
159
                ["refs", "tags"],
 
160
                ["refs", "heads"],
 
161
                ["hooks"],
 
162
                ["info"]]:
 
163
          os.mkdir(os.path.join(path, *d))
 
164
      open(os.path.join(path, 'HEAD'), 'w').write("ref: refs/heads/master\n")
 
165
      open(os.path.join(path, 'description'), 'w').write("Unnamed repository")
 
166
      open(os.path.join(path, 'info', 'excludes'), 'w').write("")
 
167
 
 
168
  create = init_bare
 
169