~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: mbp at sourcefrog
  • Date: 2005-04-09 06:21:44 UTC
  • Revision ID: mbp@sourcefrog.net-20050409062144-e47a4b64106e4c21af99beaf
debugĀ output

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
from inventory import InventoryEntry, Inventory
29
29
from osutils import isdir, quotefn, isfile, uuid, sha_file, username, chomp, \
30
30
     format_date, compact_date, pumpfile, user_email, rand_bytes, splitpath, \
31
 
     joinpath, sha_string, file_kind, local_time_offset
 
31
     joinpath, sha_string, file_kind, local_time_offset, appendpath
32
32
from store import ImmutableStore
33
33
from revision import Revision
34
 
from errors import bailout
 
34
from errors import bailout, BzrError
35
35
from textui import show_status
36
36
from diff import diff_trees
37
37
 
47
47
 
48
48
    Basically we keep looking up until we find the control directory or
49
49
    run into the root."""
50
 
    if f is None:
 
50
    if f == None:
51
51
        f = os.getcwd()
52
52
    elif hasattr(os.path, 'realpath'):
53
53
        f = os.path.realpath(f)
56
56
 
57
57
    orig_f = f
58
58
 
59
 
    last_f = f
60
59
    while True:
61
60
        if os.path.exists(os.path.join(f, bzrlib.BZRDIR)):
62
61
            return f
63
62
        head, tail = os.path.split(f)
64
63
        if head == f:
65
64
            # reached the root, whatever that may be
66
 
            bailout('%r is not in a branch' % orig_f)
 
65
            raise BzrError('%r is not in a branch' % orig_f)
67
66
        f = head
68
67
    
69
68
 
162
161
        self.controlfile('README', 'w').write(
163
162
            "This is a Bazaar-NG control directory.\n"
164
163
            "Do not change any files in this directory.")
165
 
        self.controlfile('branch-format', 'w').write(BZR_BRANCH_FORMAT)
 
164
        self.controlfile('branch-format', 'wb').write(BZR_BRANCH_FORMAT)
166
165
        for d in ('text-store', 'inventory-store', 'revision-store'):
167
166
            os.mkdir(self.controlfilename(d))
168
167
        for f in ('revision-history', 'merged-patches',
179
178
 
180
179
        In the future, we might need different in-memory Branch
181
180
        classes to support downlevel branches.  But not yet.
182
 
        """        
183
 
        # read in binary mode to detect newline wierdness.
 
181
        """
 
182
        # This ignores newlines so that we can open branches created
 
183
        # on Windows from Linux and so on.  I think it might be better
 
184
        # to always make all internal files in unix format.
184
185
        fmt = self.controlfile('branch-format', 'rb').read()
 
186
        fmt.replace('\r\n', '')
185
187
        if fmt != BZR_BRANCH_FORMAT:
186
188
            bailout('sorry, branch format %r not supported' % fmt,
187
189
                    ['use a different bzr version',
209
211
        tmpf = file(tmpfname, 'w')
210
212
        inv.write_xml(tmpf)
211
213
        tmpf.close()
212
 
        os.rename(tmpfname, self.controlfilename('inventory'))
 
214
        inv_fname = self.controlfilename('inventory')
 
215
        if sys.platform == 'win32':
 
216
            os.remove(inv_fname)
 
217
        os.rename(tmpfname, inv_fname)
213
218
        mutter('wrote working inventory')
214
219
 
215
220
 
295
300
        self._write_inventory(inv)
296
301
 
297
302
 
 
303
    def print_file(self, file, revno):
 
304
        """Print `file` to stdout."""
 
305
        tree = self.revision_tree(self.lookup_revision(revno))
 
306
        # use inventory as it was in that revision
 
307
        file_id = tree.inventory.path2id(file)
 
308
        if not file_id:
 
309
            bailout("%r is not present in revision %d" % (file, revno))
 
310
        tree.print_file(file_id)
 
311
        
298
312
 
299
313
    def remove(self, files, verbose=False):
300
314
        """Mark nominated files for removal from the inventory.
609
623
        ph = self.revision_history()
610
624
        if ph:
611
625
            return ph[-1]
612
 
 
 
626
        else:
 
627
            return None
 
628
        
613
629
 
614
630
    def lookup_revision(self, revno):
615
631
        """Return revision hash for revision number."""
620
636
            # list is 0-based; revisions are 1-based
621
637
            return self.revision_history()[revno-1]
622
638
        except IndexError:
623
 
            bailout("no such revision %s" % revno)
 
639
            raise BzrError("no such revision %s" % revno)
624
640
 
625
641
 
626
642
    def revision_tree(self, revision_id):
696
712
            precursor = p
697
713
 
698
714
 
699
 
 
700
 
    def show_status(branch, show_all=False):
 
715
    def rename_one(self, from_rel, to_rel):
 
716
        tree = self.working_tree()
 
717
        inv = tree.inventory
 
718
        if not tree.has_filename(from_rel):
 
719
            bailout("can't rename: old working file %r does not exist" % from_rel)
 
720
        if tree.has_filename(to_rel):
 
721
            bailout("can't rename: new working file %r already exists" % to_rel)
 
722
            
 
723
        file_id = inv.path2id(from_rel)
 
724
        if file_id == None:
 
725
            bailout("can't rename: old name %r is not versioned" % from_rel)
 
726
 
 
727
        if inv.path2id(to_rel):
 
728
            bailout("can't rename: new name %r is already versioned" % to_rel)
 
729
 
 
730
        to_dir, to_tail = os.path.split(to_rel)
 
731
        to_dir_id = inv.path2id(to_dir)
 
732
        if to_dir_id == None and to_dir != '':
 
733
            bailout("can't determine destination directory id for %r" % to_dir)
 
734
 
 
735
        mutter("rename_one:")
 
736
        mutter("  file_id    {%s}" % file_id)
 
737
        mutter("  from_rel   %r" % from_rel)
 
738
        mutter("  to_rel     %r" % to_rel)
 
739
        mutter("  to_dir     %r" % to_dir)
 
740
        mutter("  to_dir_id  {%s}" % to_dir_id)
 
741
            
 
742
        inv.rename(file_id, to_dir_id, to_tail)
 
743
 
 
744
        print "%s => %s" % (from_rel, to_rel)
 
745
        
 
746
        from_abs = self.abspath(from_rel)
 
747
        to_abs = self.abspath(to_rel)
 
748
        try:
 
749
            os.rename(from_abs, to_abs)
 
750
        except OSError, e:
 
751
            bailout("failed to rename %r to %r: %s"
 
752
                    % (from_abs, to_abs, e[1]),
 
753
                    ["rename rolled back"])
 
754
 
 
755
        self._write_inventory(inv)
 
756
            
 
757
 
 
758
 
 
759
    def move(self, from_paths, to_name):
 
760
        """Rename files.
 
761
 
 
762
        to_name must exist as a versioned directory.
 
763
 
 
764
        If to_name exists and is a directory, the files are moved into
 
765
        it, keeping their old names.  If it is a directory, 
 
766
 
 
767
        Note that to_name is only the last component of the new name;
 
768
        this doesn't change the directory.
 
769
        """
 
770
        ## TODO: Option to move IDs only
 
771
        assert not isinstance(from_paths, basestring)
 
772
        tree = self.working_tree()
 
773
        inv = tree.inventory
 
774
        to_abs = self.abspath(to_name)
 
775
        if not isdir(to_abs):
 
776
            bailout("destination %r is not a directory" % to_abs)
 
777
        if not tree.has_filename(to_name):
 
778
            bailout("destination %r not in working directory" % to_abs)
 
779
        to_dir_id = inv.path2id(to_name)
 
780
        if to_dir_id == None and to_name != '':
 
781
            bailout("destination %r is not a versioned directory" % to_name)
 
782
        to_dir_ie = inv[to_dir_id]
 
783
        if to_dir_ie.kind not in ('directory', 'root_directory'):
 
784
            bailout("destination %r is not a directory" % to_abs)
 
785
 
 
786
        to_idpath = Set(inv.get_idpath(to_dir_id))
 
787
 
 
788
        for f in from_paths:
 
789
            if not tree.has_filename(f):
 
790
                bailout("%r does not exist in working tree" % f)
 
791
            f_id = inv.path2id(f)
 
792
            if f_id == None:
 
793
                bailout("%r is not versioned" % f)
 
794
            name_tail = splitpath(f)[-1]
 
795
            dest_path = appendpath(to_name, name_tail)
 
796
            if tree.has_filename(dest_path):
 
797
                bailout("destination %r already exists" % dest_path)
 
798
            if f_id in to_idpath:
 
799
                bailout("can't move %r to a subdirectory of itself" % f)
 
800
 
 
801
        # OK, so there's a race here, it's possible that someone will
 
802
        # create a file in this interval and then the rename might be
 
803
        # left half-done.  But we should have caught most problems.
 
804
 
 
805
        for f in from_paths:
 
806
            name_tail = splitpath(f)[-1]
 
807
            dest_path = appendpath(to_name, name_tail)
 
808
            print "%s => %s" % (f, dest_path)
 
809
            inv.rename(inv.path2id(f), to_dir_id, name_tail)
 
810
            try:
 
811
                os.rename(self.abspath(f), self.abspath(dest_path))
 
812
            except OSError, e:
 
813
                bailout("failed to rename %r to %r: %s" % (f, dest_path, e[1]),
 
814
                        ["rename rolled back"])
 
815
 
 
816
        self._write_inventory(inv)
 
817
 
 
818
 
 
819
 
 
820
    def show_status(self, show_all=False):
701
821
        """Display single-line status for non-ignored working files.
702
822
 
703
823
        The list is show sorted in order by file name.
730
850
        # Interesting case: the old ID for a file has been removed,
731
851
        # but a new file has been created under that name.
732
852
 
733
 
        old = branch.basis_tree()
734
 
        old_inv = old.inventory
735
 
        new = branch.working_tree()
736
 
        new_inv = new.inventory
 
853
        old = self.basis_tree()
 
854
        new = self.working_tree()
737
855
 
738
856
        for fs, fid, oldname, newname, kind in diff_trees(old, new):
739
857
            if fs == 'R':
784
902
 
785
903
    def __del__(self):
786
904
        """Destroy the test branch, removing the scratch directory."""
787
 
        shutil.rmtree(self.base)
 
905
        try:
 
906
            shutil.rmtree(self.base)
 
907
        except OSError:
 
908
            # Work around for shutil.rmtree failing on Windows when
 
909
            # readonly files are encountered
 
910
            for root, dirs, files in os.walk(self.base, topdown=False):
 
911
                for name in files:
 
912
                    os.chmod(os.path.join(root, name), 0700)
 
913
            shutil.rmtree(self.base)
788
914
 
789
915
    
790
916