~ubuntu-branches/ubuntu/raring/bzr-svn/raring

« back to all changes in this revision

Viewing changes to workingtree.py

  • Committer: Bazaar Package Importer
  • Author(s): Jelmer Vernooij
  • Date: 2010-07-30 23:14:36 UTC
  • mfrom: (1.1.28 upstream) (3.3.4 sid)
  • Revision ID: james.westby@ubuntu.com-20100730231436-po8j0ibgjn2d6hy0
Tags: 1.0.3-1
* New upstream release.
 + Provides BranchConfig._get_change_editor. Closes: #572109
 + Supports more trunk layout levels. Closes: #573988
* Bump standards version to 3.9.1.
* Mark as supporting bzr 2.2.
* Suggest bzr-rewrite rather than bzr-rebase. LP: #481730

Show diffs side-by-side

added added

removed removed

Lines of Context:
51
51
    BzrDirFormat,
52
52
    BzrDir,
53
53
    Converter,
 
54
    format_registry,
54
55
    )
55
56
from bzrlib.errors import (
56
57
    BzrError,
95
96
    )
96
97
from bzrlib.plugins.svn.format import (
97
98
    SvnWorkingTreeDirFormat,
98
 
    get_rich_root_format,
99
99
    )
100
100
from bzrlib.plugins.svn.mapping import (
101
101
    escape_svn_path,
119
119
class RepositoryRootUnknown(BzrError):
120
120
    _fmt = "The working tree does not store the root of the Subversion repository."
121
121
 
 
122
class LocalRepositoryOpenFailed(BzrError):
 
123
 
 
124
    _fmt = ("Unable to open local repository at %(url)s")
 
125
 
 
126
    def __init__(self, url):
 
127
        self.url = url
 
128
 
 
129
 
122
130
def update_wc(adm, basedir, conn, revnum):
123
131
    # FIXME: honor SVN_CONFIG_SECTION_HELPERS:SVN_CONFIG_OPTION_DIFF3_CMD
124
132
    # FIXME: honor SVN_CONFIG_SECTION_MISCELLANY:SVN_CONFIG_OPTION_USE_COMMIT_TIMES
126
134
    editor = adm.get_update_editor(basedir, False, True)
127
135
    assert editor is not None
128
136
    reporter = conn.do_update(revnum, "", True, editor)
129
 
    adm.crawl_revisions(basedir, reporter, restore_files=False, 
 
137
    adm.crawl_revisions(basedir, reporter, restore_files=False,
130
138
                        recurse=True, use_commit_times=False)
131
139
    # FIXME: handle externals
132
140
 
133
141
 
134
142
def apply_prop_changes(orig_props, prop_changes):
135
143
    """Apply a set of property changes to a properties dictionary.
136
 
    
 
144
 
137
145
    :param orig_props: Dictionary with original properties (will be modified)
138
146
    :param prop_changes: Dictionary of new property values (None for deletion)
139
147
    :return: New dictionary
148
156
 
149
157
def generate_ignore_list(ignore_map):
150
158
    """Create a list of ignores, ordered by directory.
151
 
    
 
159
 
152
160
    :param ignore_map: Dictionary with paths as keys, patterns as values.
153
161
    :return: list of ignores
154
162
    """
223
231
    def get_ignore_list(self):
224
232
        """Obtain the list of ignore patterns for this working tree.
225
233
 
226
 
        :note: Will interpret the svn:ignore properties, rather than read 
 
234
        :note: Will interpret the svn:ignore properties, rather than read
227
235
               .bzrignore
228
236
        """
229
237
        ignores = set([get_adm_dir()])
232
240
        def dir_add(wc, prefix, patprefix):
233
241
            assert isinstance(prefix, unicode)
234
242
            assert isinstance(patprefix, str)
235
 
            ignorestr = wc.prop_get(properties.PROP_IGNORE, 
 
243
            ignorestr = wc.prop_get(properties.PROP_IGNORE,
236
244
                self.abspath(prefix).rstrip("/").encode("utf-8"))
237
245
            if ignorestr is not None:
238
246
                for pat in ignorestr.splitlines():
287
295
            adm.close()
288
296
        return revnum
289
297
 
290
 
    def update(self, change_reporter=None, possible_transports=None, 
 
298
    def update(self, change_reporter=None, possible_transports=None,
291
299
               revnum=None):
292
300
        """Update the workingtree to a new Bazaar revision number.
293
 
        
 
301
 
294
302
        """
295
303
        orig_revnum = self.base_revnum
296
304
        self._update_base_revnum(self._update(revnum))
297
305
        return self.base_revnum - orig_revnum
298
306
 
299
 
    def remove(self, files, verbose=False, to_file=None, keep_files=True, 
 
307
    def remove(self, files, verbose=False, to_file=None, keep_files=True,
300
308
               force=False):
301
309
        """Remove files from the working tree."""
302
310
        # FIXME: Use to_file argument
305
313
        wc = self._get_wc(write_lock=True)
306
314
        try:
307
315
            for file in files:
308
 
                wc.delete(osutils.safe_utf8(self.abspath(file)), 
 
316
                wc.delete(osutils.safe_utf8(self.abspath(file)),
309
317
                          keep_local=keep_files)
310
318
        finally:
311
319
            wc.close()
318
326
    def _get_wc(self, relpath=u"", write_lock=False, depth=0, base=None):
319
327
        """Open a working copy handle."""
320
328
        assert isinstance(relpath, unicode)
321
 
        return WorkingCopy(base, 
322
 
            self.abspath(relpath).rstrip("/").encode("utf-8"), 
 
329
        return WorkingCopy(base,
 
330
            self.abspath(relpath).rstrip("/").encode("utf-8"),
323
331
            write_lock, depth)
324
332
 
325
333
    def _get_rel_wc(self, relpath, write_lock=False):
345
353
                from_wc.delete(from_abspath)
346
354
            finally:
347
355
                from_wc.close()
348
 
            new_name = osutils.pathjoin(osutils.safe_utf8(to_dir), 
 
356
            new_name = osutils.pathjoin(osutils.safe_utf8(to_dir),
349
357
                                        osutils.safe_utf8(os.path.basename(entry)))
350
358
            self._change_fileid_mapping(self.inventory.path2id(entry), new_name)
351
359
            self._change_fileid_mapping(None, entry)
380
388
        self.read_working_inventory()
381
389
 
382
390
    def path_to_file_id(self, revnum, current_revnum, path):
383
 
        """Generate a bzr file id from a Subversion file name. 
384
 
        
 
391
        """Generate a bzr file id from a Subversion file name.
 
392
 
385
393
        :param revnum: Revision number.
386
394
        :param path: Path of the file
387
395
        :return: Tuple with file id and revision id.
400
408
 
401
409
        def add_file_to_inv(relpath, id, revid, parent_id):
402
410
            """Add a file to the inventory.
403
 
            
 
411
 
404
412
            :param relpath: Path relative to working tree root
405
413
            :param id: File id of current directory
406
414
            :param revid: Revision id
443
451
                for entry in entries.values():
444
452
                    subrelpath = osutils.pathjoin(relpath, entry.name.decode("utf-8"))
445
453
                    if entry.name == "" or entry.kind != 'directory':
446
 
                        if ((entry.copyfrom_url == url or entry.url == url) and 
 
454
                        if ((entry.copyfrom_url == url or entry.url == url) and
447
455
                            not (entry.schedule in (SCHEDULE_DELETE,
448
456
                                                    SCHEDULE_REPLACE))):
449
457
                            ret.append(osutils.pathjoin(
450
 
                                    self.get_branch_path().strip("/").decode("utf-8"), 
 
458
                                    self.get_branch_path().strip("/").decode("utf-8"),
451
459
                                    subrelpath))
452
460
                    else:
453
461
                        find_copies(url, subrelpath)
456
464
            return ret
457
465
 
458
466
        def find_ids(relpath, entry, rootwc):
459
 
            assert entry.schedule in (SCHEDULE_NORMAL, 
 
467
            assert entry.schedule in (SCHEDULE_NORMAL,
460
468
                                      SCHEDULE_DELETE,
461
469
                                      SCHEDULE_ADD,
462
470
                                      SCHEDULE_REPLACE)
463
471
            if entry.schedule == SCHEDULE_NORMAL:
464
472
                assert entry.revision >= 0
465
473
                # Keep old id
466
 
                return self.path_to_file_id(entry.cmt_rev, entry.revision, 
 
474
                return self.path_to_file_id(entry.cmt_rev, entry.revision,
467
475
                        relpath)
468
476
            elif entry.schedule == SCHEDULE_DELETE:
469
477
                return (None, None)
470
 
            elif (entry.schedule == SCHEDULE_ADD or 
 
478
            elif (entry.schedule == SCHEDULE_ADD or
471
479
                  entry.schedule == SCHEDULE_REPLACE):
472
480
                # See if the file this file was copied from disappeared
473
481
                # and has no other copies -> in that case, take id of other file
474
 
                if (entry.copyfrom_url and 
 
482
                if (entry.copyfrom_url and
475
483
                    list(find_copies(entry.copyfrom_url)) == [relpath.encode("utf-8")]):
476
 
                    return self.path_to_file_id(entry.copyfrom_rev, 
 
484
                    return self.path_to_file_id(entry.copyfrom_rev,
477
485
                        entry.revision, self.unprefix(urllib.unquote(entry.copyfrom_url[len(entry.repos):])).decode("utf-8"))
478
486
                ids = self._get_new_file_ids()
479
487
                if ids.has_key(relpath):
507
515
 
508
516
                entry = entries[name]
509
517
                assert entry
510
 
                
 
518
 
511
519
                if entry.kind == subvertpy.NODE_DIR:
512
520
                    try:
513
521
                        subwc = self._get_wc(subrelpath, base=wc)
528
536
                    else:
529
537
                        mutter('no id for %r', entry.url)
530
538
 
531
 
        rootwc = self._get_wc() 
 
539
        rootwc = self._get_wc()
532
540
        try:
533
541
            add_dir_to_inv(u"", rootwc, None)
534
542
        finally:
573
581
                except NoSuchRevision:
574
582
                    pass
575
583
 
576
 
            adm.prop_set(svk.SVN_PROP_SVK_MERGE, 
 
584
            adm.prop_set(svk.SVN_PROP_SVK_MERGE,
577
585
                         svk.serialize_svk_features(svk_merges), self.basedir.encode("utf-8"))
578
586
        finally:
579
587
            adm.close()
635
643
            kinds = [self._kind(file) for file in files]
636
644
        assert isinstance(files, list)
637
645
        for f, kind, file_id, copyfrom in zip(files, kinds, ids, _copyfrom):
638
 
            wc = self._get_wc(os.path.dirname(osutils.safe_unicode(f)), 
 
646
            wc = self._get_wc(os.path.dirname(osutils.safe_unicode(f)),
639
647
                              write_lock=True)
640
648
            try:
641
649
                try:
677
685
        self._set_base(None, fetched)
678
686
        self.read_working_inventory()
679
687
 
680
 
    def pull(self, source, overwrite=False, stop_revision=None, 
 
688
    def pull(self, source, overwrite=False, stop_revision=None,
681
689
             delta_reporter=None, possible_transports=None, local=False):
682
690
        """Pull in changes from another branch into this working tree."""
683
691
        # FIXME: Use delta_reporter
684
692
        # FIXME: Use source
685
693
        # FIXME: Use overwrite
686
 
        result = self.branch.pull(source, overwrite=overwrite, stop_revision=stop_revision, 
 
694
        result = self.branch.pull(source, overwrite=overwrite, stop_revision=stop_revision,
687
695
                                  local=local)
688
696
        fetched = self._update(self.branch.get_revnum())
689
697
        self._update_base_revnum(fetched)
771
779
    def _get_svk_merges(self, base_branch_props):
772
780
        return base_branch_props.get(svk.SVN_PROP_SVK_MERGE, "")
773
781
 
774
 
    def _apply_inventory_delta_change(self, base_tree, old_path, new_path, 
 
782
    def _apply_inventory_delta_change(self, base_tree, old_path, new_path,
775
783
                                      file_id, ie):
776
784
        already_there = (old_path == new_path and base_tree._inventory[file_id].kind == ie.kind)
777
785
        if old_path is not None:
778
786
            old_abspath = osutils.safe_utf8(self.abspath(old_path))
779
787
            if not already_there:
780
788
                self.remove([old_path], keep_files=True)
781
 
            copyfrom = (urlutils.join(self.entry.url, old_path), 
 
789
            copyfrom = (urlutils.join(self.entry.url, old_path),
782
790
                        self.base_revnum)
783
791
        else:
784
792
            try:
828
836
        if kind == 'file':
829
837
            size = stat_result.st_size
830
838
            # try for a stat cache lookup
831
 
            executable = self._is_executable_from_path_and_stat(path, 
 
839
            executable = self._is_executable_from_path_and_stat(path,
832
840
                stat_result)
833
841
            return (kind, size, executable, self._sha_from_stat(
834
842
                path, stat_result))
840
848
            return (kind, None, None, None)
841
849
 
842
850
    def _get_base_revmeta(self):
843
 
        return self.branch.repository._revmeta_provider.lookup_revision(self.get_branch_path(self.base_revnum), self.base_revnum)
 
851
        return self.branch.repository._revmeta_provider.lookup_revision(
 
852
            self.get_branch_path(self.base_revnum), self.base_revnum)
844
853
 
845
854
    def _reset_data(self):
846
855
        pass
912
921
            except KeyError:
913
922
                revmeta, mapping = self.branch.repository._get_revmeta(revid)
914
923
                revprops = revmeta.get_revprops()
915
 
                ret = (revmeta.revnum, 
 
924
                ret = (revmeta.revnum,
916
925
                       revprops[properties.PROP_REVISION_DATE],
917
926
                       revprops.get(properties.PROP_REVISION_AUTHOR, ""))
918
927
                simple_revprops_cache[revid] = ret
937
946
                name = name.decode("utf-8")
938
947
                if name == "":
939
948
                    fileprops = newrevtree.get_file_properties(id, path)
940
 
                    process_committed(adm, path, fileprops, 
 
949
                    process_committed(adm, path, fileprops,
941
950
                                  newrevtree.inventory[id].revision)
942
951
                    continue
943
952
 
965
974
                    target_f.write(source_f.read())
966
975
                    target_f.close()
967
976
                    source_f.close()
968
 
                    fileprops = newrevtree.get_file_properties(child_id, 
 
977
                    fileprops = newrevtree.get_file_properties(child_id,
969
978
                            child_path)
970
979
                    process_committed(adm, child_path, fileprops,
971
980
                                  newrevtree.inventory[child_id].revision)
1005
1014
 
1006
1015
 
1007
1016
class SvnCheckout(BzrDir):
1008
 
    """BzrDir implementation for Subversion checkouts (directories 
 
1017
    """BzrDir implementation for Subversion checkouts (directories
1009
1018
    containing a .svn subdirectory."""
1010
1019
 
1011
1020
    def __init__(self, transport, format):
1015
1024
        # Open related remote repository + branch
1016
1025
        try:
1017
1026
            wc = WorkingCopy(None, self.local_path.encode("utf-8"))
1018
 
        except subvertpy.SubversionException, (msg, ERR_WC_UNSUPPORTED_FORMAT):
1019
 
            raise UnsupportedFormatError(msg, kind='workingtree')
 
1027
        except subvertpy.SubversionException, (msg, num):
 
1028
            if num == ERR_WC_UNSUPPORTED_FORMAT:
 
1029
                raise UnsupportedFormatError(msg, kind='workingtree')
 
1030
            else:
 
1031
                raise
1020
1032
        try:
1021
1033
            self.entry = wc.entry(self.local_path.encode("utf-8"), True)
1022
1034
        finally:
1055
1067
        except bzrsvn_errors.NotSvnBranchPath, e:
1056
1068
            raise NoWorkingTree(self.local_path)
1057
1069
 
1058
 
    def sprout(self, url, revision_id=None, force_new_repo=False, 
 
1070
    def sprout(self, url, revision_id=None, force_new_repo=False,
1059
1071
               recurse='down', possible_transports=None, accelerator_tree=None,
1060
1072
               hardlink=False):
1061
1073
        # FIXME: honor force_new_repo
1062
1074
        # FIXME: Use recurse
1063
 
        result = get_rich_root_format().initialize(url)
 
1075
        result = format_registry.make_bzrdir('default').initialize(url)
1064
1076
        repo = self._find_repository()
1065
1077
        repo.clone(result, revision_id)
1066
1078
        branch = self.open_branch()
1081
1093
        if self.entry.repos is None:
1082
1094
            return self.get_remote_bzrdir().find_repository()
1083
1095
        if self._remote_repo_transport is None:
1084
 
            self._remote_repo_transport = SvnRaTransport(self.entry.repos, from_transport=self._remote_branch_transport)
 
1096
            try:
 
1097
                self._remote_repo_transport = SvnRaTransport(self.entry.repos, from_transport=self._remote_branch_transport)
 
1098
            except subvertpy.SubversionException, (msg, num):
 
1099
                if num == subvertpy.ERR_RA_LOCAL_REPOS_OPEN_FAILED:
 
1100
                    raise LocalRepositoryOpenFailed(self.entry.repos)
 
1101
                else:
 
1102
                    raise
1085
1103
        return SvnRepository(self, self._remote_repo_transport,
1086
1104
                self.get_branch_path())
1087
1105