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

  • Committer: Gustav Hartvigsson
  • Date: 2021-01-09 21:36:27 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20210109213627-h1xwcutzy9m7a99b
Added 'Case Preserving Working Tree Use Cases' from Canonical Wiki

* Addod a page from the Canonical Bazaar wiki
  with information on the scmeatics of case
  perserving filesystems an a case insensitive
  filesystem works.
  
  * Needs re-work, but this will do as it is the
    same inforamoton as what was on the linked
    page in the currint documentation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
"""An adapter between a Git control dir and a Bazaar ControlDir."""
19
19
 
20
 
from __future__ import absolute_import
 
20
import contextlib
21
21
 
22
22
from .. import (
23
23
    branch as _mod_branch,
26
26
    osutils,
27
27
    urlutils,
28
28
    )
29
 
from ..sixish import (
30
 
    PY3,
31
 
    viewitems,
32
 
    )
33
29
from ..transport import (
34
30
    do_catching_redirections,
35
31
    get_transport_from_path,
43
39
    RepositoryAcquisitionPolicy,
44
40
    )
45
41
 
 
42
from .mapping import (
 
43
    decode_git_path,
 
44
    encode_git_path,
 
45
    )
46
46
from .push import (
47
47
    GitPushResult,
48
48
    )
182
182
        result_branch = source_branch.sprout(
183
183
            result, revision_id=revision_id, repository=result_repo)
184
184
        if (create_tree_if_local and
 
185
            result.open_branch(name="").name == result_branch.name and
185
186
            isinstance(target_transport, LocalTransport) and
186
187
                (result_repo is None or result_repo.make_working_trees())):
187
 
            result.create_workingtree(
 
188
            wt = result.create_workingtree(
188
189
                accelerator_tree=accelerator_tree,
189
190
                hardlink=hardlink, from_branch=result_branch)
 
191
        else:
 
192
            wt = None
 
193
        if recurse == 'down':
 
194
            with contextlib.ExitStack() as stack:
 
195
                basis = None
 
196
                if wt is not None:
 
197
                    basis = wt.basis_tree()
 
198
                elif result_branch is not None:
 
199
                    basis = result_branch.basis_tree()
 
200
                elif source_branch is not None:
 
201
                    basis = source_branch.basis_tree()
 
202
                if basis is not None:
 
203
                    stack.enter_context(basis.lock_read())
 
204
                    subtrees = basis.iter_references()
 
205
                else:
 
206
                    subtrees = []
 
207
                for path in subtrees:
 
208
                    target = urlutils.join(url, urlutils.escape(path))
 
209
                    sublocation = wt.reference_parent(
 
210
                        path, possible_transports=possible_transports)
 
211
                    if sublocation is None:
 
212
                        trace.warning(
 
213
                            'Ignoring nested tree %s, parent location unknown.',
 
214
                            path)
 
215
                        continue
 
216
                    sublocation.controldir.sprout(
 
217
                        target, basis.get_reference_revision(path),
 
218
                        force_new_repo=force_new_repo, recurse=recurse,
 
219
                        stacked=stacked)
 
220
        if getattr(result_repo, '_git', None):
 
221
            # Don't leak resources:
 
222
            # TODO(jelmer): This shouldn't be git-specific, and possibly
 
223
            # just use read locks.
 
224
            result_repo._git.object_store.close()
190
225
        return result
191
226
 
192
227
    def clone_on_transport(self, transport, revision_id=None,
193
228
                           force_new_repo=False, preserve_stacking=False,
194
229
                           stacked_on=None, create_prefix=False,
195
 
                           use_existing_dir=True, no_tree=False):
 
230
                           use_existing_dir=True, no_tree=False,
 
231
                           tag_selector=None):
196
232
        """See ControlDir.clone_on_transport."""
197
233
        from ..repository import InterRepository
198
234
        from .mapping import default_mapping
 
235
        from ..transport.local import LocalTransport
199
236
        if stacked_on is not None:
200
237
            raise _mod_branch.UnstackableBranchFormat(
201
238
                self._format, self.user_url)
214
251
        interrepo = InterRepository.get(source_repo, target_repo)
215
252
        if revision_id is not None:
216
253
            determine_wants = interrepo.get_determine_wants_revids(
217
 
                [revision_id], include_tags=True)
 
254
                [revision_id], include_tags=True, tag_selector=tag_selector)
218
255
        else:
219
256
            determine_wants = interrepo.determine_wants_all
220
257
        (pack_hint, _, refs) = interrepo.fetch_objects(determine_wants,
221
258
                                                       mapping=default_mapping)
222
 
        for name, val in viewitems(refs):
 
259
        for name, val in refs.items():
223
260
            target_git_repo.refs[name] = val
224
 
        result_dir = self.__class__(transport, target_git_repo, format)
 
261
        result_dir = LocalGitDir(transport, target_git_repo, format)
225
262
        if revision_id is not None:
226
263
            result_dir.open_branch().set_last_revision(revision_id)
227
 
        try:
228
 
            # Cheaper to check if the target is not local, than to try making
229
 
            # the tree and fail.
230
 
            result_dir.root_transport.local_abspath('.')
 
264
        if not no_tree and isinstance(result_dir.root_transport, LocalTransport):
231
265
            if result_dir.open_repository().make_working_trees():
232
 
                self.open_workingtree().clone(
233
 
                    result_dir, revision_id=revision_id)
234
 
        except (brz_errors.NoWorkingTree, brz_errors.NotLocalUrl):
235
 
            pass
 
266
                try:
 
267
                    local_wt = self.open_workingtree()
 
268
                except brz_errors.NoWorkingTree:
 
269
                    pass
 
270
                except brz_errors.NotLocalUrl:
 
271
                    result_dir.create_workingtree(revision_id=revision_id)
 
272
                else:
 
273
                    local_wt.clone(result_dir, revision_id=revision_id)
236
274
 
237
275
        return result_dir
238
276
 
267
305
        """
268
306
        return UseExistingRepository(self.find_repository())
269
307
 
 
308
    def branch_names(self):
 
309
        from .refs import ref_to_branch_name
 
310
        ret = []
 
311
        for ref in self.get_refs_container().keys():
 
312
            try:
 
313
                branch_name = ref_to_branch_name(ref)
 
314
            except UnicodeDecodeError:
 
315
                trace.warning("Ignoring branch %r with unicode error ref", ref)
 
316
                continue
 
317
            except ValueError:
 
318
                continue
 
319
            ret.append(branch_name)
 
320
        return ret
 
321
 
270
322
    def get_branches(self):
271
323
        from .refs import ref_to_branch_name
272
324
        ret = {}
273
325
        for ref in self.get_refs_container().keys():
274
326
            try:
275
327
                branch_name = ref_to_branch_name(ref)
276
 
            except ValueError:
277
 
                continue
278
328
            except UnicodeDecodeError:
279
329
                trace.warning("Ignoring branch %r with unicode error ref", ref)
280
330
                continue
 
331
            except ValueError:
 
332
                continue
281
333
            ret[branch_name] = self.open_branch(ref=ref)
282
334
        return ret
283
335
 
286
338
 
287
339
    def push_branch(self, source, revision_id=None, overwrite=False,
288
340
                    remember=False, create_prefix=False, lossy=False,
289
 
                    name=None):
 
341
                    name=None, tag_selector=None):
290
342
        """Push the source branch into this ControlDir."""
291
343
        push_result = GitPushResult()
292
344
        push_result.workingtree_updated = None
299
351
        target = self.open_branch(name, nascent_ok=True)
300
352
        push_result.branch_push_result = source.push(
301
353
            target, overwrite=overwrite, stop_revision=revision_id,
302
 
            lossy=lossy)
 
354
            lossy=lossy, tag_selector=tag_selector)
303
355
        push_result.new_revid = push_result.branch_push_result.new_revid
304
356
        push_result.old_revid = push_result.branch_push_result.old_revid
 
357
        try:
 
358
            wt = self.open_workingtree()
 
359
        except brz_errors.NoWorkingTree:
 
360
            push_result.workingtree_updated = None
 
361
        else:
 
362
            if self.open_branch(name="").name == target.name:
 
363
                wt._update_git_tree(
 
364
                    old_revision=push_result.old_revid,
 
365
                    new_revision=push_result.new_revid)
 
366
                push_result.workingtree_updated = True
 
367
            else:
 
368
                push_result.workingtree_updated = False
305
369
        push_result.target_branch = target
306
370
        if source.get_push_location() is None or remember:
307
371
            source.set_push_location(push_result.target_branch.base)
338
402
        from .transportgit import TransportRepo
339
403
 
340
404
        def _open(transport):
341
 
            return TransportRepo(transport, self.bare,
342
 
                                 refs_text=getattr(self, "_refs_text", None))
 
405
            try:
 
406
                return TransportRepo(transport, self.bare,
 
407
                                     refs_text=getattr(self, "_refs_text", None))
 
408
            except ValueError as e:
 
409
                if e.args == ('Expected file to start with \'gitdir: \'', ):
 
410
                    raise brz_errors.NotBranchError(path=transport.base)
 
411
                raise
343
412
 
344
413
        def redirected(transport, e, redirection_notice):
345
414
            trace.note(redirection_notice)
346
415
            return transport._redirected_to(e.source, e.target)
347
416
        gitrepo = do_catching_redirections(_open, transport, redirected)
348
 
        if not gitrepo._controltransport.has('HEAD'):
 
417
        if not _found and not gitrepo._controltransport.has('objects'):
349
418
            raise brz_errors.NotBranchError(path=transport.base)
350
419
        return LocalGitDir(transport, gitrepo, self)
351
420
 
363
432
                                   stack_on_pwd=None, repo_format_name=None,
364
433
                                   make_working_trees=None,
365
434
                                   shared_repo=False, vfs_only=False):
 
435
        if shared_repo:
 
436
            raise brz_errors.SharedRepositoriesUnsupported(self)
 
437
 
366
438
        def make_directory(transport):
367
439
            transport.mkdir('.')
368
440
            return transport
401
473
            raise brz_errors.NotBranchError(path=transport.base)
402
474
        return external_url.startswith("file:")
403
475
 
 
476
    def is_control_filename(self, filename):
 
477
        return (filename == '.git'
 
478
                or filename.startswith('.git/')
 
479
                or filename.startswith('.git\\'))
 
480
 
404
481
 
405
482
class BareLocalGitControlDirFormat(LocalGitControlDirFormat):
406
483
 
410
487
    def get_format_description(self):
411
488
        return "Local Git Repository (bare)"
412
489
 
 
490
    def is_control_filename(self, filename):
 
491
        return False
 
492
 
413
493
 
414
494
class LocalGitDir(GitDir):
415
495
    """An adapter to the '.git' dir used by git."""
443
523
            self.transport = transport.clone('.git')
444
524
        self._mode_check_done = None
445
525
 
446
 
    def is_control_filename(self, filename):
447
 
        return (filename == '.git'
448
 
                or filename.startswith('.git/')
449
 
                or filename.startswith('.git\\'))
450
 
 
451
526
    def _get_symref(self, ref):
452
527
        ref_chain, unused_sha = self._git.refs.follow(ref)
453
528
        if len(ref_chain) == 1:
471
546
                    target_branch._format, self._format)
472
547
            # TODO(jelmer): Do some consistency checking across branches..
473
548
            self.control_transport.put_bytes(
474
 
                'commondir', target_path.encode('utf-8'))
 
549
                'commondir', encode_git_path(target_path))
475
550
            # TODO(jelmer): Urgh, avoid mucking about with internals.
476
551
            self._git._commontransport = (
477
552
                target_branch.repository._git._commontransport.clone())
511
586
                base_url = self.user_url.rstrip('/')
512
587
            else:
513
588
                base_url = urlutils.local_path_to_url(
514
 
                    commondir.decode(osutils._fs_enc)).rstrip('/.git/') + '/'
515
 
            if not PY3:
516
 
                params = {k: v.encode('utf-8') for (k, v) in viewitems(params)}
 
589
                    decode_git_path(commondir)).rstrip('/.git/') + '/'
517
590
            return urlutils.join_segment_parameters(base_url, params)
518
591
        return None
519
592