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

  • Committer: Martin Pool
  • Date: 2005-06-15 09:24:48 UTC
  • Revision ID: mbp@sourcefrog.net-20050615092448-e625e44b98681196
- notes on tracking multiple parents

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
from cStringIO import StringIO
20
 
 
21
 
from dulwich.errors import (
22
 
    NotGitRepository,
23
 
    NoIndexPresent,
24
 
    )
25
 
from dulwich.objects import (
26
 
    ShaFile,
27
 
    )
28
 
from dulwich.object_store import (
29
 
    PackBasedObjectStore,
30
 
    PACKDIR,
31
 
    )
32
 
from dulwich.pack import (
33
 
    PackData,
34
 
    Pack,
35
 
    iter_sha1,
36
 
    load_pack_index_file,
37
 
    write_pack_index_v2,
38
 
    )
39
 
from dulwich.repo import (
40
 
    BaseRepo,
41
 
    DictRefsContainer,
42
 
    OBJECTDIR,
43
 
    read_info_refs,
44
 
    )
45
 
 
46
 
from bzrlib.errors import (
47
 
    FileExists,
48
 
    NoSuchFile,
49
 
    TransportNotPossible,
50
 
    )
51
 
 
52
 
 
53
 
class TransportRepo(BaseRepo):
54
 
 
55
 
    def __init__(self, transport):
56
 
        self.transport = transport
57
 
        try:
58
 
            if self.transport.has(".git/info/refs"):
59
 
                self.bare = False
60
 
                self._controltransport = self.transport.clone('.git')
61
 
            elif self.transport.has("info/refs"):
62
 
                self.bare = True
63
 
                self._controltransport = self.transport
64
 
            else:
65
 
                raise NotGitRepository(self.transport)
66
 
        except NoSuchFile:
67
 
            raise NotGitRepository(self.transport)
68
 
        object_store = TransportObjectStore(
69
 
            self._controltransport.clone(OBJECTDIR))
70
 
        refs = {}
71
 
        refs["HEAD"] = self._controltransport.get_bytes("HEAD").rstrip("\n")
72
 
        refs.update(read_info_refs(self._controltransport.get('info/refs')))
73
 
        super(TransportRepo, self).__init__(object_store, 
74
 
                DictRefsContainer(refs))
75
 
 
76
 
    def get_named_file(self, path):
77
 
        """Get a file from the control dir with a specific name.
78
 
 
79
 
        Although the filename should be interpreted as a filename relative to
80
 
        the control dir in a disk-baked Repo, the object returned need not be
81
 
        pointing to a file in that location.
82
 
 
83
 
        :param path: The path to the file, relative to the control dir.
84
 
        :return: An open file object, or None if the file does not exist.
85
 
        """
86
 
        try:
87
 
            return self._controltransport.get(path.lstrip('/'))
88
 
        except NoSuchFile:
89
 
            return None
90
 
 
91
 
    def open_index(self):
92
 
        """Open the index for this repository."""
93
 
        raise NoIndexPresent()
94
 
 
95
 
    def __repr__(self):
96
 
        return "<TransportRepo for %r>" % self.transport
97
 
 
98
 
 
99
 
class TransportObjectStore(PackBasedObjectStore):
100
 
    """Git-style object store that exists on disk."""
101
 
 
102
 
    def __init__(self, transport):
103
 
        """Open an object store.
104
 
 
105
 
        :param transport: Transport to open data from
106
 
        """
107
 
        super(TransportObjectStore, self).__init__()
108
 
        self.transport = transport
109
 
        self.pack_transport = self.transport.clone(PACKDIR)
110
 
    
111
 
    def _pack_cache_stale(self):
112
 
        return False # FIXME
113
 
 
114
 
    def _pack_names(self):
115
 
        try:
116
 
            f = self.transport.get('info/packs')
117
 
        except NoSuchFile:
118
 
            return self.pack_transport.list_dir(".")
119
 
        else:
120
 
            ret = []
121
 
            for line in f.readlines():
122
 
                line = line.rstrip("\n")
123
 
                if not line:
124
 
                    continue
125
 
                (kind, name) = line.split(" ", 1)
126
 
                if kind != "P":
127
 
                    continue
128
 
                ret.append(name)
129
 
            return ret
130
 
 
131
 
    def _load_packs(self):
132
 
        ret = []
133
 
        for name in self._pack_names():
134
 
            if name.startswith("pack-") and name.endswith(".pack"):
135
 
                try:
136
 
                    size = self.pack_transport.stat(name).st_size
137
 
                except TransportNotPossible:
138
 
                    def pd():
139
 
                        # FIXME: This reads the whole pack file at once
140
 
                        f = self.pack_transport.get(name)
141
 
                        contents = f.read()
142
 
                        return PackData(name, StringIO(contents), size=len(contents))
143
 
                else:
144
 
                    pd = lambda: PackData(name, self.pack_transport.get(name),
145
 
                            size=size)
146
 
                idxname = name.replace(".pack", ".idx")
147
 
                idx = lambda: load_pack_index_file(idxname, self.pack_transport.get(idxname))
148
 
                pack = Pack.from_lazy_objects(pd, idx)
149
 
                ret.append(pack)
150
 
        return ret
151
 
 
152
 
    def _iter_loose_objects(self):
153
 
        for base in self.transport.list_dir('.'):
154
 
            if len(base) != 2:
155
 
                continue
156
 
            for rest in self.transport.list_dir(base):
157
 
                yield base+rest
158
 
 
159
 
    def _split_loose_object(self, sha):
160
 
        return (sha[:2], sha[2:])
161
 
 
162
 
    def _get_loose_object(self, sha):
163
 
        path = '%s/%s' % self._split_loose_object(sha)
164
 
        try:
165
 
            return ShaFile.from_file(self.transport.get(path))
166
 
        except NoSuchFile:
167
 
            return None
168
 
 
169
 
    def add_object(self, obj):
170
 
        """Add a single object to this object store.
171
 
 
172
 
        :param obj: Object to add
173
 
        """
174
 
        (dir, file) = self._split_loose_object(obj.id)
175
 
        try:
176
 
            self.transport.mkdir(dir)
177
 
        except FileExists:
178
 
            pass
179
 
        path = "%s/%s" % (dir, file)
180
 
        if self.transport.has(path):
181
 
            return # Already there, no need to write again
182
 
        self.transport.put_bytes(path, obj.as_legacy_object())
183
 
 
184
 
    def move_in_pack(self, f):
185
 
        """Move a specific file containing a pack into the pack directory.
186
 
 
187
 
        :note: The file should be on the same file system as the
188
 
            packs directory.
189
 
 
190
 
        :param path: Path to the pack file.
191
 
        """
192
 
        f.seek(0)
193
 
        p = PackData(None, f, len(f.getvalue()))
194
 
        entries = p.sorted_entries()
195
 
        basename = "pack-%s" % iter_sha1(entry[0] for entry in entries)
196
 
        f.seek(0)
197
 
        self.pack_transport.put_file(basename + ".pack", f)
198
 
        idxfile = StringIO()
199
 
        write_pack_index_v2(idxfile, entries, p.get_stored_checksum())
200
 
        idxfile.seek(0)
201
 
        self.pack_transport.put_file(basename + ".idx", idxfile)
202
 
        idxfile.seek(0)
203
 
        idx = load_pack_index_file(basename+".idx", idxfile)
204
 
        final_pack = Pack.from_objects(p, idx)
205
 
        self._add_known_pack(final_pack)
206
 
        return final_pack
207
 
 
208
 
    def add_pack(self):
209
 
        """Add a new pack to this object store. 
210
 
 
211
 
        :return: Fileobject to write to and a commit function to 
212
 
            call when the pack is finished.
213
 
        """
214
 
        from cStringIO import StringIO
215
 
        f = StringIO()
216
 
        def commit():
217
 
            if len(f.getvalue()) > 0:
218
 
                return self.move_in_pack(f)
219
 
            else:
220
 
                return None
221
 
        return f, commit
222
 
 
223
 
    @classmethod
224
 
    def init(cls, transport):
225
 
        transport.mkdir('info')
226
 
        transport.mkdir(PACKDIR)
227
 
        return cls(transport)