/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.246.1 by Jelmer Vernooij
Add TransportRepo class.
1
# Copyright (C) 2010 Jelmer Vernooij <jelmer@samba.org>
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""A Git repository implementation that uses a Bazaar transport."""
18
19
20
from dulwich.errors import (
21
    NotGitRepository,
0.246.7 by Jelmer Vernooij
more work.
22
    NoIndexPresent,
0.246.1 by Jelmer Vernooij
Add TransportRepo class.
23
    )
0.246.4 by Jelmer Vernooij
more work on transportgit.
24
from dulwich.objects import (
25
    ShaFile,
26
    )
27
from dulwich.object_store import (
28
    PackBasedObjectStore,
29
    PACKDIR,
30
    )
31
from dulwich.pack import (
0.246.7 by Jelmer Vernooij
more work.
32
    PackData,
0.246.4 by Jelmer Vernooij
more work on transportgit.
33
    Pack,
0.200.936 by Jelmer Vernooij
Test transportgit.
34
    iter_sha1,
0.246.7 by Jelmer Vernooij
more work.
35
    load_pack_index_file,
0.200.936 by Jelmer Vernooij
Test transportgit.
36
    write_pack_index_v2,
0.246.4 by Jelmer Vernooij
more work on transportgit.
37
    )
0.246.1 by Jelmer Vernooij
Add TransportRepo class.
38
from dulwich.repo import (
39
    BaseRepo,
0.246.8 by Jelmer Vernooij
simplify refs handling.
40
    DictRefsContainer,
0.246.1 by Jelmer Vernooij
Add TransportRepo class.
41
    OBJECTDIR,
0.246.8 by Jelmer Vernooij
simplify refs handling.
42
    read_info_refs,
0.246.1 by Jelmer Vernooij
Add TransportRepo class.
43
    )
44
45
from bzrlib.errors import (
0.200.933 by Jelmer Vernooij
Allow directories to already exist :-)
46
    FileExists,
0.246.1 by Jelmer Vernooij
Add TransportRepo class.
47
    NoSuchFile,
48
    )
49
50
51
class TransportRepo(BaseRepo):
52
53
    def __init__(self, transport):
54
        self.transport = transport
0.200.720 by Jelmer Vernooij
Avoid loading bzr-git/dulwich when not necessary.
55
        try:
56
            if self.transport.has(".git/info/refs"):
57
                self.bare = False
58
                self._controltransport = self.transport.clone('.git')
59
            elif self.transport.has("info/refs"):
60
                self.bare = True
61
                self._controltransport = self.transport
62
            else:
63
                raise NotGitRepository(self.transport)
64
        except NoSuchFile:
0.246.1 by Jelmer Vernooij
Add TransportRepo class.
65
            raise NotGitRepository(self.transport)
66
        object_store = TransportObjectStore(
67
            self._controltransport.clone(OBJECTDIR))
0.246.8 by Jelmer Vernooij
simplify refs handling.
68
        refs = {}
69
        refs["HEAD"] = self._controltransport.get_bytes("HEAD").rstrip("\n")
70
        refs.update(read_info_refs(self._controltransport.get('info/refs')))
71
        super(TransportRepo, self).__init__(object_store, 
72
                DictRefsContainer(refs))
0.246.1 by Jelmer Vernooij
Add TransportRepo class.
73
74
    def get_named_file(self, path):
75
        """Get a file from the control dir with a specific name.
76
77
        Although the filename should be interpreted as a filename relative to
78
        the control dir in a disk-baked Repo, the object returned need not be
79
        pointing to a file in that location.
80
81
        :param path: The path to the file, relative to the control dir.
82
        :return: An open file object, or None if the file does not exist.
83
        """
84
        try:
85
            return self._controltransport.get(path.lstrip('/'))
86
        except NoSuchFile:
87
            return None
88
89
    def open_index(self):
90
        """Open the index for this repository."""
0.246.9 by Jelmer Vernooij
Remove unused write code.
91
        raise NoIndexPresent()
0.246.1 by Jelmer Vernooij
Add TransportRepo class.
92
93
    def __repr__(self):
94
        return "<TransportRepo for %r>" % self.transport
95
0.246.4 by Jelmer Vernooij
more work on transportgit.
96
97
class TransportObjectStore(PackBasedObjectStore):
98
    """Git-style object store that exists on disk."""
99
100
    def __init__(self, transport):
101
        """Open an object store.
102
103
        :param transport: Transport to open data from
104
        """
105
        super(TransportObjectStore, self).__init__()
106
        self.transport = transport
107
        self.pack_transport = self.transport.clone(PACKDIR)
0.200.889 by Jelmer Vernooij
Fix fetching over HTTP. We really need tests for this...
108
    
109
    def _pack_cache_stale(self):
110
        return False # FIXME
0.246.4 by Jelmer Vernooij
more work on transportgit.
111
0.200.935 by Jelmer Vernooij
Allow using manual listing for pack contents.
112
    def _pack_names(self):
113
        try:
114
            f = self.transport.get('info/packs')
115
        except NoSuchFile:
116
            return self.pack_transport.list_dir(".")
117
        else:
118
            ret = []
119
            for line in f.readlines():
120
                line = line.rstrip("\n")
121
                if not line:
122
                    continue
123
                (kind, name) = line.split(" ", 1)
124
                if kind != "P":
125
                    continue
126
                ret.append(name)
127
            return ret
128
0.246.4 by Jelmer Vernooij
more work on transportgit.
129
    def _load_packs(self):
0.246.7 by Jelmer Vernooij
more work.
130
        ret = []
0.200.935 by Jelmer Vernooij
Allow using manual listing for pack contents.
131
        for name in self._pack_names():
0.246.9 by Jelmer Vernooij
Remove unused write code.
132
            if name.startswith("pack-") and name.endswith(".pack"):
0.200.936 by Jelmer Vernooij
Test transportgit.
133
                size = self.pack_transport.stat(name).st_size
134
                pd = PackData(name, self.pack_transport.get(name), size=size)
0.246.9 by Jelmer Vernooij
Remove unused write code.
135
                idxname = name.replace(".pack", ".idx")
136
                idx = load_pack_index_file(idxname, self.pack_transport.get(idxname))
137
                ret.append(Pack.from_objects(pd, idx))
0.246.7 by Jelmer Vernooij
more work.
138
        return ret
0.246.4 by Jelmer Vernooij
more work on transportgit.
139
140
    def _iter_loose_objects(self):
141
        for base in self.transport.list_dir('.'):
142
            if len(base) != 2:
143
                continue
144
            for rest in self.transport.list_dir(base):
145
                yield base+rest
146
147
    def _split_loose_object(self, sha):
148
        return (sha[:2], sha[2:])
149
150
    def _get_loose_object(self, sha):
151
        path = '%s/%s' % self._split_loose_object(sha)
152
        try:
0.200.903 by Jelmer Vernooij
Fix compatibility with newer versions of Dulwich.
153
            return ShaFile.from_file(self.transport.get(path))
0.246.4 by Jelmer Vernooij
more work on transportgit.
154
        except NoSuchFile:
155
            return None
156
157
    def add_object(self, obj):
158
        """Add a single object to this object store.
159
160
        :param obj: Object to add
161
        """
162
        (dir, file) = self._split_loose_object(obj.id)
0.200.933 by Jelmer Vernooij
Allow directories to already exist :-)
163
        try:
164
            self.transport.mkdir(dir)
165
        except FileExists:
166
            pass
0.246.4 by Jelmer Vernooij
more work on transportgit.
167
        path = "%s/%s" % (dir, file)
168
        if self.transport.has(path):
169
            return # Already there, no need to write again
170
        self.transport.put_bytes(path, obj.as_legacy_object())
171
0.200.936 by Jelmer Vernooij
Test transportgit.
172
    def move_in_pack(self, path):
173
        """Move a specific file containing a pack into the pack directory.
174
175
        :note: The file should be on the same file system as the
176
            packs directory.
177
178
        :param path: Path to the pack file.
179
        """
180
        import os
181
        p = PackData(path)
182
        entries = p.sorted_entries()
183
        basename = os.path.join(self.pack_transport.local_abspath('.'),
184
            "pack-%s" % iter_sha1(entry[0] for entry in entries))
185
        write_pack_index_v2(basename+".idx", entries, p.get_stored_checksum())
186
        p.close()
187
        os.rename(path, basename + ".pack")
188
        final_pack = Pack(basename)
189
        self._add_known_pack(final_pack)
190
        return final_pack
191
0.246.4 by Jelmer Vernooij
more work on transportgit.
192
    def add_pack(self):
193
        """Add a new pack to this object store. 
194
195
        :return: Fileobject to write to and a commit function to 
196
            call when the pack is finished.
197
        """
0.200.936 by Jelmer Vernooij
Test transportgit.
198
        import os, tempfile
199
        fd, path = tempfile.mkstemp(dir=self.pack_transport.local_abspath('.'), suffix=".pack")
200
        f = os.fdopen(fd, 'wb')
201
        def commit():
202
            f.close()
203
            if os.path.getsize(path) > 0:
204
                return self.move_in_pack(path)
205
            else:
206
                return None
207
        return f, commit
0.200.934 by Jelmer Vernooij
Add init function.
208
209
    @classmethod
210
    def init(cls, transport):
211
        transport.mkdir('info')
212
        transport.mkdir(PACKDIR)
213
        return cls(transport)