/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 bzrlib/branch.py

  • Committer: Aaron Bentley
  • Date: 2005-11-25 04:30:47 UTC
  • mfrom: (1508.1.15)
  • mto: (1185.65.14 storage)
  • mto: This revision was merged to the branch mainline in revision 1550.
  • Revision ID: aaron.bentley@utoronto.ca-20051125043047-420c01b3982f9cda
MergedĀ theĀ mainline

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
 
25
25
 
26
26
import bzrlib
27
 
from bzrlib.inventory import InventoryEntry
28
27
import bzrlib.inventory as inventory
29
28
from bzrlib.trace import mutter, note
30
 
from bzrlib.osutils import (isdir, quotefn, compact_date, rand_bytes, 
 
29
from bzrlib.osutils import (isdir, quotefn,
31
30
                            rename, splitpath, sha_file, appendpath, 
32
31
                            file_kind, abspath)
33
32
import bzrlib.errors as errors
188
187
        """Return the id of this branches root"""
189
188
        raise NotImplementedError('get_root_id is abstract')
190
189
 
191
 
    def set_root_id(self, file_id):
192
 
        raise NotImplementedError('set_root_id is abstract')
193
 
 
194
 
    def add(self, files, ids=None):
195
 
        """Make files versioned.
196
 
 
197
 
        Note that the command line normally calls smart_add instead,
198
 
        which can automatically recurse.
199
 
 
200
 
        This puts the files in the Added state, so that they will be
201
 
        recorded by the next commit.
202
 
 
203
 
        files
204
 
            List of paths to add, relative to the base of the tree.
205
 
 
206
 
        ids
207
 
            If set, use these instead of automatically generated ids.
208
 
            Must be the same length as the list of files, but may
209
 
            contain None for ids that are to be autogenerated.
210
 
 
211
 
        TODO: Perhaps have an option to add the ids even if the files do
212
 
              not (yet) exist.
213
 
 
214
 
        TODO: Perhaps yield the ids and paths as they're added.
215
 
        """
216
 
        raise NotImplementedError('add is abstract')
217
 
 
218
190
    def print_file(self, file, revno):
219
191
        """Print `file` to stdout."""
220
192
        raise NotImplementedError('print_file is abstract')
221
193
 
222
 
    def unknowns(self):
223
 
        """Return all unknown files.
224
 
 
225
 
        These are files in the working directory that are not versioned or
226
 
        control files or ignored.
227
 
        
228
 
        >>> from bzrlib.workingtree import WorkingTree
229
 
        >>> b = ScratchBranch(files=['foo', 'foo~'])
230
 
        >>> map(str, b.unknowns())
231
 
        ['foo']
232
 
        >>> b.add('foo')
233
 
        >>> list(b.unknowns())
234
 
        []
235
 
        >>> WorkingTree(b.base, b).remove('foo')
236
 
        >>> list(b.unknowns())
237
 
        [u'foo']
238
 
        """
239
 
        raise NotImplementedError('unknowns is abstract')
240
 
 
241
194
    def append_revision(self, *revision_ids):
242
195
        raise NotImplementedError('append_revision is abstract')
243
196
 
359
312
        return history[revno - 1]
360
313
 
361
314
    def working_tree(self):
362
 
        """Return a `Tree` for the working copy."""
 
315
        """Return a `Tree` for the working copy if this is a local branch."""
363
316
        raise NotImplementedError('working_tree is abstract')
364
317
 
365
318
    def pull(self, source, overwrite=False):
621
574
                            'or remove the .bzr directory'
622
575
                            ' and "bzr init" again'])
623
576
 
 
577
    @needs_read_lock
624
578
    def get_root_id(self):
625
579
        """See Branch.get_root_id."""
626
580
        inv = self.storage.get_inventory(self.last_revision())
638
592
        self.storage.unlock()
639
593
        LockableFiles.unlock(self)
640
594
 
641
 
    @needs_write_lock
642
 
    def set_root_id(self, file_id):
643
 
        """See Branch.set_root_id."""
644
 
        inv = self.working_tree().read_working_inventory()
645
 
        orig_root_id = inv.root.file_id
646
 
        del inv._byid[inv.root.file_id]
647
 
        inv.root.file_id = file_id
648
 
        inv._byid[inv.root.file_id] = inv.root
649
 
        for fid in inv:
650
 
            entry = inv[fid]
651
 
            if entry.parent_id in (None, orig_root_id):
652
 
                entry.parent_id = inv.root.file_id
653
 
        self._write_inventory(inv)
654
 
 
655
 
    @needs_write_lock
656
 
    def add(self, files, ids=None):
657
 
        """See Branch.add."""
658
 
        # TODO: Re-adding a file that is removed in the working copy
659
 
        # should probably put it back with the previous ID.
660
 
        if isinstance(files, basestring):
661
 
            assert(ids is None or isinstance(ids, basestring))
662
 
            files = [files]
663
 
            if ids is not None:
664
 
                ids = [ids]
665
 
 
666
 
        if ids is None:
667
 
            ids = [None] * len(files)
668
 
        else:
669
 
            assert(len(ids) == len(files))
670
 
 
671
 
        inv = self.working_tree().read_working_inventory()
672
 
        for f,file_id in zip(files, ids):
673
 
            if is_control_file(f):
674
 
                raise BzrError("cannot add control file %s" % quotefn(f))
675
 
 
676
 
            fp = splitpath(f)
677
 
 
678
 
            if len(fp) == 0:
679
 
                raise BzrError("cannot add top-level %r" % f)
680
 
 
681
 
            fullpath = os.path.normpath(self.abspath(f))
682
 
 
683
 
            try:
684
 
                kind = file_kind(fullpath)
685
 
            except OSError:
686
 
                # maybe something better?
687
 
                raise BzrError('cannot add: not a regular file, symlink or directory: %s' % quotefn(f))
688
 
 
689
 
            if not InventoryEntry.versionable_kind(kind):
690
 
                raise BzrError('cannot add: not a versionable file ('
691
 
                               'i.e. regular file, symlink or directory): %s' % quotefn(f))
692
 
 
693
 
            if file_id is None:
694
 
                file_id = gen_file_id(f)
695
 
            inv.add_path(f, kind=kind, file_id=file_id)
696
 
 
697
 
            mutter("add file %s file_id:{%s} kind=%r" % (f, file_id, kind))
698
 
 
699
 
        self.working_tree()._write_inventory(inv)
700
 
 
701
595
    @needs_read_lock
702
596
    def print_file(self, file, revno):
703
597
        """See Branch.print_file."""
704
598
        return self.storage.print_file(file, self.get_rev_id(revno))
705
599
 
706
 
    def unknowns(self):
707
 
        """See Branch.unknowns."""
708
 
        return self.working_tree().unknowns()
709
 
 
710
600
    @needs_write_lock
711
601
    def append_revision(self, *revision_ids):
712
602
        """See Branch.append_revision."""
795
685
    def working_tree(self):
796
686
        """See Branch.working_tree."""
797
687
        from bzrlib.workingtree import WorkingTree
798
 
        # TODO: In the future, perhaps WorkingTree should utilize Transport
799
 
        # RobertCollins 20051003 - I don't think it should - working trees are
800
 
        # much more complex to keep consistent than our careful .bzr subset.
801
 
        # instead, we should say that working trees are local only, and optimise
802
 
        # for that.
803
688
        if self._transport.base.find('://') != -1:
804
689
            raise NoWorkingTree(self.base)
805
690
        return WorkingTree(self.base, branch=self)
818
703
        finally:
819
704
            source.unlock()
820
705
 
821
 
    @needs_write_lock
822
 
    def rename_one(self, from_rel, to_rel):
823
 
        """See Branch.rename_one."""
824
 
        tree = self.working_tree()
825
 
        inv = tree.inventory
826
 
        if not tree.has_filename(from_rel):
827
 
            raise BzrError("can't rename: old working file %r does not exist" % from_rel)
828
 
        if tree.has_filename(to_rel):
829
 
            raise BzrError("can't rename: new working file %r already exists" % to_rel)
830
 
 
831
 
        file_id = inv.path2id(from_rel)
832
 
        if file_id == None:
833
 
            raise BzrError("can't rename: old name %r is not versioned" % from_rel)
834
 
 
835
 
        if inv.path2id(to_rel):
836
 
            raise BzrError("can't rename: new name %r is already versioned" % to_rel)
837
 
 
838
 
        to_dir, to_tail = os.path.split(to_rel)
839
 
        to_dir_id = inv.path2id(to_dir)
840
 
        if to_dir_id == None and to_dir != '':
841
 
            raise BzrError("can't determine destination directory id for %r" % to_dir)
842
 
 
843
 
        mutter("rename_one:")
844
 
        mutter("  file_id    {%s}" % file_id)
845
 
        mutter("  from_rel   %r" % from_rel)
846
 
        mutter("  to_rel     %r" % to_rel)
847
 
        mutter("  to_dir     %r" % to_dir)
848
 
        mutter("  to_dir_id  {%s}" % to_dir_id)
849
 
 
850
 
        inv.rename(file_id, to_dir_id, to_tail)
851
 
 
852
 
        from_abs = self.abspath(from_rel)
853
 
        to_abs = self.abspath(to_rel)
854
 
        try:
855
 
            rename(from_abs, to_abs)
856
 
        except OSError, e:
857
 
            raise BzrError("failed to rename %r to %r: %s"
858
 
                    % (from_abs, to_abs, e[1]),
859
 
                    ["rename rolled back"])
860
 
 
861
 
        self.working_tree()._write_inventory(inv)
862
 
 
863
 
    @needs_write_lock
864
 
    def move(self, from_paths, to_name):
865
 
        """See Branch.move."""
866
 
        result = []
867
 
        ## TODO: Option to move IDs only
868
 
        assert not isinstance(from_paths, basestring)
869
 
        tree = self.working_tree()
870
 
        inv = tree.inventory
871
 
        to_abs = self.abspath(to_name)
872
 
        if not isdir(to_abs):
873
 
            raise BzrError("destination %r is not a directory" % to_abs)
874
 
        if not tree.has_filename(to_name):
875
 
            raise BzrError("destination %r not in working directory" % to_abs)
876
 
        to_dir_id = inv.path2id(to_name)
877
 
        if to_dir_id == None and to_name != '':
878
 
            raise BzrError("destination %r is not a versioned directory" % to_name)
879
 
        to_dir_ie = inv[to_dir_id]
880
 
        if to_dir_ie.kind not in ('directory', 'root_directory'):
881
 
            raise BzrError("destination %r is not a directory" % to_abs)
882
 
 
883
 
        to_idpath = inv.get_idpath(to_dir_id)
884
 
 
885
 
        for f in from_paths:
886
 
            if not tree.has_filename(f):
887
 
                raise BzrError("%r does not exist in working tree" % f)
888
 
            f_id = inv.path2id(f)
889
 
            if f_id == None:
890
 
                raise BzrError("%r is not versioned" % f)
891
 
            name_tail = splitpath(f)[-1]
892
 
            dest_path = appendpath(to_name, name_tail)
893
 
            if tree.has_filename(dest_path):
894
 
                raise BzrError("destination %r already exists" % dest_path)
895
 
            if f_id in to_idpath:
896
 
                raise BzrError("can't move %r to a subdirectory of itself" % f)
897
 
 
898
 
        # OK, so there's a race here, it's possible that someone will
899
 
        # create a file in this interval and then the rename might be
900
 
        # left half-done.  But we should have caught most problems.
901
 
 
902
 
        for f in from_paths:
903
 
            name_tail = splitpath(f)[-1]
904
 
            dest_path = appendpath(to_name, name_tail)
905
 
            result.append((f, dest_path))
906
 
            inv.rename(inv.path2id(f), to_dir_id, name_tail)
907
 
            try:
908
 
                rename(self.abspath(f), self.abspath(dest_path))
909
 
            except OSError, e:
910
 
                raise BzrError("failed to rename %r to %r: %s" % (f, dest_path, e[1]),
911
 
                        ["rename rolled back"])
912
 
 
913
 
        self.working_tree()._write_inventory(inv)
914
 
        return result
915
 
 
916
706
    def get_parent(self):
917
707
        """See Branch.get_parent."""
918
708
        import errno
1039
829
            break
1040
830
        filename = head
1041
831
    return False
1042
 
 
1043
 
 
1044
 
 
1045
 
def gen_file_id(name):
1046
 
    """Return new file id.
1047
 
 
1048
 
    This should probably generate proper UUIDs, but for the moment we
1049
 
    cope with just randomness because running uuidgen every time is
1050
 
    slow."""
1051
 
    import re
1052
 
    from binascii import hexlify
1053
 
    from time import time
1054
 
 
1055
 
    # get last component
1056
 
    idx = name.rfind('/')
1057
 
    if idx != -1:
1058
 
        name = name[idx+1 : ]
1059
 
    idx = name.rfind('\\')
1060
 
    if idx != -1:
1061
 
        name = name[idx+1 : ]
1062
 
 
1063
 
    # make it not a hidden file
1064
 
    name = name.lstrip('.')
1065
 
 
1066
 
    # remove any wierd characters; we don't escape them but rather
1067
 
    # just pull them out
1068
 
    name = re.sub(r'[^\w.]', '', name)
1069
 
 
1070
 
    s = hexlify(rand_bytes(8))
1071
 
    return '-'.join((name, compact_date(time()), s))
1072
 
 
1073
 
 
1074
 
def gen_root_id():
1075
 
    """Return a new tree-root file id."""
1076
 
    return gen_file_id('TREE_ROOT')
1077
 
 
1078