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

Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2007 Canonical Ltd
 
2
# Copyright (C) 2010 Jelmer Vernooij
2
3
#
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
14
15
# along with this program; if not, write to the Free Software
15
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
 
17
 
"""An adapter between a Git control dir and a Bazaar BzrDir"""
18
 
 
19
 
import os
20
 
 
21
 
import bzrlib
22
 
from bzrlib.lazy_import import lazy_import
 
18
"""An adapter between a Git control dir and a Bazaar ControlDir."""
 
19
 
23
20
from bzrlib import (
24
 
    bzrdir,
 
21
    errors as bzr_errors,
25
22
    lockable_files,
26
23
    urlutils,
 
24
    version_info as bzrlib_version,
27
25
    )
28
26
 
29
 
lazy_import(globals(), """
30
 
from bzrlib.lockable_files import TransportLock
 
27
LockWarner = getattr(lockable_files, "_LockWarner", None)
 
28
 
31
29
from bzrlib.plugins.git import (
32
 
    errors,
33
 
    branch,
34
 
    repository,
35
 
    workingtree,
 
30
    LocalGitControlDirFormat,
36
31
    )
37
 
""")
38
 
 
 
32
try:
 
33
    from bzrlib.controldir import (
 
34
        ControlDir,
 
35
        format_registry,
 
36
        )
 
37
except ImportError:
 
38
    # bzr < 2.3
 
39
    from bzrlib.bzrdir import (
 
40
        BzrDir,
 
41
        format_registry,
 
42
        )
 
43
    ControlDir = BzrDir
39
44
 
40
45
 
41
46
class GitLock(object):
56
61
    def validate_token(self, token):
57
62
        pass
58
63
 
 
64
    def break_lock(self):
 
65
        pass
 
66
 
59
67
 
60
68
class GitLockableFiles(lockable_files.LockableFiles):
61
69
    """Git specific lockable files abstraction."""
64
72
        self._lock = lock
65
73
        self._transaction = None
66
74
        self._lock_mode = None
67
 
        self._lock_count = 0
68
75
        self._transport = transport
69
 
 
70
 
 
71
 
class GitDir(bzrdir.BzrDir):
 
76
        if LockWarner is None:
 
77
            # Bzr 1.13
 
78
            self._lock_count = 0
 
79
        else:
 
80
            self._lock_warner = LockWarner(repr(self))
 
81
 
 
82
 
 
83
class GitDirConfig(object):
 
84
 
 
85
    def get_default_stack_on(self):
 
86
        return None
 
87
 
 
88
    def set_default_stack_on(self, value):
 
89
        raise bzr_errors.BzrError("Cannot set configuration")
 
90
 
 
91
 
 
92
class GitDir(ControlDir):
72
93
    """An adapter to the '.git' dir used by git."""
73
94
 
74
95
    def is_supported(self):
75
96
        return True
76
97
 
 
98
    def can_convert_format(self):
 
99
        return False
 
100
 
 
101
    def break_lock(self):
 
102
        pass
 
103
 
77
104
    def cloning_metadir(self, stacked=False):
78
 
        if stacked:
79
 
            return bzrlib.bzrdir.format_registry.make_bzrdir("pack-0.92")
80
 
        else:
81
 
            return bzrlib.bzrdir.format_registry.make_bzrdir("1.6")
 
105
        return format_registry.make_bzrdir("default")
 
106
 
 
107
    def _branch_name_to_ref(self, name):
 
108
        raise NotImplementedError(self._branch_name_to_ref)
 
109
 
 
110
    if bzrlib_version >= (2, 2):
 
111
        def open_branch(self, name=None, unsupported=False, 
 
112
            ignore_fallbacks=None):
 
113
            return self._open_branch(name=name,
 
114
                ignore_fallbacks=ignore_fallbacks, unsupported=unsupported)
 
115
    else:
 
116
        def open_branch(self, ignore_fallbacks=None, unsupported=False):
 
117
            return self._open_branch(name=None,
 
118
                ignore_fallbacks=ignore_fallbacks, unsupported=unsupported)
 
119
 
 
120
    def get_config(self):
 
121
        return GitDirConfig()
82
122
 
83
123
 
84
124
class LocalGitDir(GitDir):
85
125
    """An adapter to the '.git' dir used by git."""
86
126
 
87
 
    _gitrepository_class = repository.LocalGitRepository
 
127
    def _get_gitrepository_class(self):
 
128
        from bzrlib.plugins.git.repository import LocalGitRepository
 
129
        return LocalGitRepository
 
130
 
 
131
    _gitrepository_class = property(_get_gitrepository_class)
 
132
 
 
133
    @property
 
134
    def user_transport(self):
 
135
        return self.root_transport
 
136
 
 
137
    @property
 
138
    def control_transport(self):
 
139
        return self.transport
88
140
 
89
141
    def __init__(self, transport, lockfiles, gitrepo, format):
90
142
        self._format = format
91
143
        self.root_transport = transport
 
144
        self._mode_check_done = False
92
145
        self._git = gitrepo
93
146
        if gitrepo.bare:
94
147
            self.transport = transport
95
148
        else:
96
149
            self.transport = transport.clone('.git')
97
150
        self._lockfiles = lockfiles
98
 
 
99
 
    def get_branch_transport(self, branch_format):
 
151
        self._mode_check_done = None
 
152
 
 
153
    def _branch_name_to_ref(self, name):
 
154
        from bzrlib.plugins.git.refs import branch_name_to_ref
 
155
        ref = branch_name_to_ref(name, None)
 
156
        if ref == "HEAD":
 
157
            from dulwich.repo import SYMREF
 
158
            refcontents = self._git.refs.read_ref(ref)
 
159
            if refcontents.startswith(SYMREF):
 
160
                ref = refcontents[len(SYMREF):]
 
161
        return ref
 
162
 
 
163
    def is_control_filename(self, filename):
 
164
        return filename == '.git' or filename.startswith('.git/')
 
165
 
 
166
    def get_branch_transport(self, branch_format, name=None):
100
167
        if branch_format is None:
101
168
            return self.transport
102
 
        if isinstance(branch_format, LocalGitBzrDirFormat):
103
 
            return self.transport
104
 
        raise errors.bzr_errors.IncompatibleFormat(branch_format, self._format)
105
 
 
106
 
    get_repository_transport = get_branch_transport
107
 
    get_workingtree_transport = get_branch_transport
108
 
 
109
 
    def open_branch(self, ignored=None):
 
169
        if isinstance(branch_format, LocalGitControlDirFormat):
 
170
            return self.transport
 
171
        raise bzr_errors.IncompatibleFormat(branch_format, self._format)
 
172
 
 
173
    def get_repository_transport(self, format):
 
174
        if format is None:
 
175
            return self.transport
 
176
        if isinstance(format, LocalGitControlDirFormat):
 
177
            return self.transport
 
178
        raise bzr_errors.IncompatibleFormat(format, self._format)
 
179
 
 
180
    def get_workingtree_transport(self, format):
 
181
        if format is None:
 
182
            return self.transport
 
183
        if isinstance(format, LocalGitControlDirFormat):
 
184
            return self.transport
 
185
        raise bzr_errors.IncompatibleFormat(format, self._format)
 
186
 
 
187
    def _open_branch(self, name=None, ignore_fallbacks=None, unsupported=False):
110
188
        """'create' a branch for this dir."""
111
189
        repo = self.open_repository()
112
 
        return branch.LocalGitBranch(self, repo, "HEAD", repo._git.head(), self._lockfiles)
 
190
        from bzrlib.plugins.git.branch import LocalGitBranch
 
191
        return LocalGitBranch(self, repo, self._branch_name_to_ref(name),
 
192
            self._lockfiles)
 
193
 
 
194
    def destroy_branch(self, name=None):
 
195
        refname = self._branch_name_to_ref(name)
 
196
        if not refname in self._git.refs:
 
197
            raise bzr_errors.NotBranchError(self.root_transport.base,
 
198
                    bzrdir=self)
 
199
        del self._git.refs[refname]
 
200
 
 
201
    def destroy_repository(self):
 
202
        raise bzr_errors.UnsupportedOperation(self.destroy_repository, self)
 
203
 
 
204
    def destroy_workingtree(self):
 
205
        raise bzr_errors.UnsupportedOperation(self.destroy_workingtree, self)
 
206
 
 
207
    def needs_format_conversion(self, format=None):
 
208
        return not isinstance(self._format, format.__class__)
 
209
 
 
210
    def list_branches(self):
 
211
        ret = []
 
212
        for name in self._git.get_refs():
 
213
            if name.startswith("refs/heads/"):
 
214
                ret.append(self.open_branch(name=name))
 
215
        return ret
113
216
 
114
217
    def open_repository(self, shared=False):
115
218
        """'open' a repository for this dir."""
116
219
        return self._gitrepository_class(self, self._lockfiles)
117
220
 
118
221
    def open_workingtree(self, recommend_upgrade=True):
119
 
        if self._git.bare:
120
 
            loc = urlutils.unescape_for_display(self.root_transport.base, 'ascii')
121
 
            raise errors.bzr_errors.NoWorkingTree(loc)
122
 
        else:
123
 
            return workingtree.GitWorkingTree(self, self.open_repository(), 
124
 
                                                  self.open_branch())
 
222
        if not self._git.bare:
 
223
            from dulwich.errors import NoIndexPresent
 
224
            repo = self.open_repository()
 
225
            try:
 
226
                index = repo._git.open_index()
 
227
            except NoIndexPresent:
 
228
                pass
 
229
            else:
 
230
                from bzrlib.plugins.git.workingtree import GitWorkingTree
 
231
                try:
 
232
                    branch = self.open_branch()
 
233
                except bzr_errors.NotBranchError:
 
234
                    pass
 
235
                else:
 
236
                    return GitWorkingTree(self, repo, branch, index)
 
237
        loc = urlutils.unescape_for_display(self.root_transport.base, 'ascii')
 
238
        raise bzr_errors.NoWorkingTree(loc)
125
239
 
126
240
    def create_repository(self, shared=False):
127
241
        return self.open_repository()
128
242
 
129
 
 
130
 
class GitBzrDirFormat(bzrdir.BzrDirFormat):
131
 
    _lock_class = TransportLock
132
 
 
133
 
    def is_supported(self):
134
 
        return True
135
 
 
136
 
 
137
 
class LocalGitBzrDirFormat(GitBzrDirFormat):
138
 
    """The .git directory control format."""
139
 
 
140
 
    _gitdir_class = LocalGitDir
141
 
 
142
 
    @classmethod
143
 
    def _known_formats(self):
144
 
        return set([LocalGitBzrDirFormat()])
145
 
 
146
 
    def open(self, transport, _found=None):
147
 
        """Open this directory.
148
 
 
149
 
        """
150
 
        from bzrlib.plugins.git import git
151
 
        # we dont grok readonly - git isn't integrated with transport.
152
 
        url = transport.base
153
 
        if url.startswith('readonly+'):
154
 
            url = url[len('readonly+'):]
155
 
 
156
 
        try:
157
 
            gitrepo = git.repo.Repo(transport.local_abspath("."))
158
 
        except errors.bzr_errors.NotLocalUrl:
159
 
            raise errors.bzr_errors.NotBranchError(path=transport.base)
160
 
        lockfiles = GitLockableFiles(transport, GitLock())
161
 
        return self._gitdir_class(transport, lockfiles, gitrepo, self)
162
 
 
163
 
    @classmethod
164
 
    def probe_transport(klass, transport):
165
 
        """Our format is present if the transport ends in '.not/'."""
166
 
        from bzrlib.plugins.git import git
167
 
        # little ugly, but works
168
 
        format = klass()
169
 
        # delegate to the main opening code. This pays a double rtt cost at the
170
 
        # moment, so perhaps we want probe_transport to return the opened thing
171
 
        # rather than an openener ? or we could return a curried thing with the
172
 
        # dir to open already instantiated ? Needs more thought.
173
 
        try:
174
 
            format.open(transport)
175
 
            return format
176
 
        except git.errors.NotGitRepository, e:
177
 
            raise errors.bzr_errors.NotBranchError(path=transport.base)
178
 
        raise errors.bzr_errors.NotBranchError(path=transport.base)
179
 
 
180
 
    def get_format_description(self):
181
 
        return "Local Git Repository"
182
 
 
183
 
    def get_format_string(self):
184
 
        return "Local Git Repository"
185
 
 
186
 
    def initialize_on_transport(self, transport):
187
 
        from bzrlib.transport.local import LocalTransport
188
 
        from bzrlib.plugins.git import git
189
 
 
190
 
        if not isinstance(transport, LocalTransport):
191
 
            raise NotImplementedError(self.initialize, 
192
 
                "Can't create Git Repositories/branches on "
193
 
                "non-local transports")
194
 
 
195
 
        git.repo.Repo.create(transport.local_abspath(".")) 
196
 
        return self.open(transport)
197
 
 
198
 
    def is_supported(self):
199
 
        return True
200
 
 
201
 
 
202
 
class RemoteGitBzrDirFormat(GitBzrDirFormat):
203
 
    """The .git directory control format."""
204
 
 
205
 
    @classmethod
206
 
    def _known_formats(self):
207
 
        return set([RemoteGitBzrDirFormat()])
208
 
 
209
 
    def open(self, transport, _found=None):
210
 
        """Open this directory.
211
 
 
212
 
        """
213
 
        from bzrlib.plugins.git.remote import RemoteGitDir, GitSmartTransport
214
 
        if not isinstance(transport, GitSmartTransport):
215
 
            raise errors.bzr_errors.NotBranchError(transport.base)
216
 
        # we dont grok readonly - git isn't integrated with transport.
217
 
        url = transport.base
218
 
        if url.startswith('readonly+'):
219
 
            url = url[len('readonly+'):]
220
 
 
221
 
        lockfiles = GitLockableFiles(transport, GitLock())
222
 
        return RemoteGitDir(transport, lockfiles, self)
223
 
 
224
 
    @classmethod
225
 
    def probe_transport(klass, transport):
226
 
        """Our format is present if the transport ends in '.not/'."""
227
 
        # little ugly, but works
228
 
        format = klass()
229
 
        from bzrlib.plugins.git.remote import GitSmartTransport
230
 
        if not isinstance(transport, GitSmartTransport):
231
 
            raise errors.bzr_errors.NotBranchError(transport.base)
232
 
        # The only way to know a path exists and contains a valid repository 
233
 
        # is to do a request against it:
234
 
        try:
235
 
            transport.fetch_pack(lambda x: [], None, lambda x: None, 
236
 
                                 lambda x: mutter("git: %s" % x))
237
 
        except GitProtocolException, e:
238
 
            raise errors.bzr_errors.NotBranchError(path=transport.base)
239
 
        else:
240
 
            return format
241
 
        raise errors.bzr_errors.NotBranchError(path=transport.base)
242
 
 
243
 
    def get_format_description(self):
244
 
        return "Remote Git Repository"
245
 
 
246
 
    def get_format_string(self):
247
 
        return "Remote Git Repository"
248
 
 
249
 
    def initialize_on_transport(self, transport):
250
 
        raise errors.bzr_errors.UninitializableFormat(self)
 
243
    def create_branch(self, name=None):
 
244
        refname = self._branch_name_to_ref(name)
 
245
        from dulwich.protocol import ZERO_SHA
 
246
        self._git.refs[refname or "HEAD"] = ZERO_SHA
 
247
        return self.open_branch(name)
 
248
 
 
249
    def backup_bzrdir(self):
 
250
        if self._git.bare:
 
251
            self.root_transport.copy_tree(".git", ".git.backup")
 
252
            return (self.root_transport.abspath(".git"),
 
253
                    self.root_transport.abspath(".git.backup"))
 
254
        else:
 
255
            raise bzr_errors.BzrError("Unable to backup bare repositories")
 
256
 
 
257
    def create_workingtree(self, revision_id=None, from_branch=None,
 
258
        accelerator_tree=None, hardlink=False):
 
259
        if self._git.bare:
 
260
            raise bzr_errors.BzrError("Can't create working tree in a bare repo")
 
261
        from dulwich.index import write_index
 
262
        from dulwich.pack import SHA1Writer
 
263
        f = open(self.transport.local_abspath("index"), 'w+')
 
264
        try:
 
265
            f = SHA1Writer(f)
 
266
            write_index(f, [])
 
267
        finally:
 
268
            f.close()
 
269
        return self.open_workingtree()
 
270
 
 
271
    def find_repository(self):
 
272
        """Find the repository that should be used.
 
273
 
 
274
        This does not require a branch as we use it to find the repo for
 
275
        new branches as well as to hook existing branches up to their
 
276
        repository.
 
277
        """
 
278
        return self.open_repository()
 
279
 
 
280
    def _find_creation_modes(self):
 
281
        """Determine the appropriate modes for files and directories.
 
282
 
 
283
        They're always set to be consistent with the base directory,
 
284
        assuming that this transport allows setting modes.
 
285
        """
 
286
        # TODO: Do we need or want an option (maybe a config setting) to turn
 
287
        # this off or override it for particular locations? -- mbp 20080512
 
288
        if self._mode_check_done:
 
289
            return
 
290
        self._mode_check_done = True
 
291
        try:
 
292
            st = self.transport.stat('.')
 
293
        except TransportNotPossible:
 
294
            self._dir_mode = None
 
295
            self._file_mode = None
 
296
        else:
 
297
            # Check the directory mode, but also make sure the created
 
298
            # directories and files are read-write for this user. This is
 
299
            # mostly a workaround for filesystems which lie about being able to
 
300
            # write to a directory (cygwin & win32)
 
301
            if (st.st_mode & 07777 == 00000):
 
302
                # FTP allows stat but does not return dir/file modes
 
303
                self._dir_mode = None
 
304
                self._file_mode = None
 
305
            else:
 
306
                self._dir_mode = (st.st_mode & 07777) | 00700
 
307
                # Remove the sticky and execute bits for files
 
308
                self._file_mode = self._dir_mode & ~07111
 
309
 
 
310
    def _get_file_mode(self):
 
311
        """Return Unix mode for newly created files, or None.
 
312
        """
 
313
        if not self._mode_check_done:
 
314
            self._find_creation_modes()
 
315
        return self._file_mode
 
316
 
 
317
    def _get_dir_mode(self):
 
318
        """Return Unix mode for newly created directories, or None.
 
319
        """
 
320
        if not self._mode_check_done:
 
321
            self._find_creation_modes()
 
322
        return self._dir_mode
 
323
 
251
324