~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Martin Pool
  • Date: 2005-03-12 07:16:39 UTC
  • Revision ID: mbp@sourcefrog.net-20050312071639-0a8f59a34a024ff0
cope when gecos field doesn't have a comma

reported by ysaito, rooneg -- thanks

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Canonical Ltd
 
1
#! /usr/bin/env python
 
2
# -*- coding: UTF-8 -*-
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
40
41
 
41
42
 
42
43
 
43
 
def find_branch_root(f=None):
44
 
    """Find the branch root enclosing f, or pwd.
45
 
 
46
 
    It is not necessary that f exists.
47
 
 
48
 
    Basically we keep looking up until we find the control directory or
49
 
    run into the root."""
50
 
    if f is None:
51
 
        f = os.getcwd()
52
 
    elif hasattr(os.path, 'realpath'):
53
 
        f = os.path.realpath(f)
54
 
    else:
55
 
        f = os.path.abspath(f)
56
 
 
57
 
    orig_f = f
58
 
 
59
 
    last_f = f
60
 
    while True:
61
 
        if os.path.exists(os.path.join(f, bzrlib.BZRDIR)):
62
 
            return f
63
 
        head, tail = os.path.split(f)
64
 
        if head == f:
65
 
            # reached the root, whatever that may be
66
 
            bailout('%r is not in a branch' % orig_f)
67
 
        f = head
68
 
    
69
44
 
70
45
 
71
46
######################################################################
87
62
 
88
63
    :todo: mkdir() method.
89
64
    """
90
 
    def __init__(self, base, init=False, find_root=True):
 
65
    def __init__(self, base, init=False):
91
66
        """Create new branch object at a particular location.
92
67
 
93
68
        :param base: Base directory for the branch.
94
 
        
 
69
 
95
70
        :param init: If True, create new control files in a previously
96
71
             unversioned directory.  If False, the branch must already
97
72
             be versioned.
98
73
 
99
 
        :param find_root: If true and init is false, find the root of the
100
 
             existing branch containing base.
101
 
 
102
74
        In the test suite, creation of new trees is tested using the
103
75
        `ScratchBranch` class.
104
76
        """
 
77
        self.base = os.path.realpath(base)
105
78
        if init:
106
 
            self.base = os.path.realpath(base)
107
79
            self._make_control()
108
 
        elif find_root:
109
 
            self.base = find_branch_root(base)
110
80
        else:
111
 
            self.base = os.path.realpath(base)
112
81
            if not isdir(self.controlfilename('.')):
113
82
                bailout("not a bzr branch: %s" % quotefn(base),
114
83
                        ['use "bzr init" to initialize a new working tree',
115
84
                         'current bzr can only operate from top-of-tree'])
116
 
        self._check_format()
 
85
            self._check_format()
117
86
 
118
87
        self.text_store = ImmutableStore(self.controlfilename('text-store'))
119
88
        self.revision_store = ImmutableStore(self.controlfilename('revision-store'))
127
96
    __repr__ = __str__
128
97
 
129
98
 
130
 
    def abspath(self, name):
131
 
        """Return absolute filename for something in the branch"""
 
99
    def _rel(self, name):
 
100
        """Return filename relative to branch top"""
132
101
        return os.path.join(self.base, name)
133
 
 
134
 
 
135
 
    def relpath(self, path):
136
 
        """Return path relative to this branch of something inside it.
137
 
 
138
 
        Raises an error if path is not in this branch."""
139
 
        rp = os.path.realpath(path)
140
 
        # FIXME: windows
141
 
        if not rp.startswith(self.base):
142
 
            bailout("path %r is not within branch %r" % (rp, self.base))
143
 
        rp = rp[len(self.base):]
144
 
        rp = rp.lstrip(os.sep)
145
 
        return rp
146
 
 
 
102
        
147
103
 
148
104
    def controlfilename(self, file_or_path):
149
105
        """Return location relative to branch."""
204
160
        will be committed to the next revision.
205
161
        """
206
162
        ## TODO: factor out to atomicfile?  is rename safe on windows?
207
 
        ## TODO: Maybe some kind of clean/dirty marker on inventory?
208
163
        tmpfname = self.controlfilename('inventory.tmp')
209
164
        tmpf = file(tmpfname, 'w')
210
165
        inv.write_xml(tmpf)
273
228
            if len(fp) == 0:
274
229
                bailout("cannot add top-level %r" % f)
275
230
                
276
 
            fullpath = os.path.normpath(self.abspath(f))
277
 
 
278
 
            try:
279
 
                kind = file_kind(fullpath)
280
 
            except OSError:
281
 
                # maybe something better?
282
 
                bailout('cannot add: not a regular file or directory: %s' % quotefn(f))
283
 
            
284
 
            if kind != 'file' and kind != 'directory':
285
 
                bailout('cannot add: not a regular file or directory: %s' % quotefn(f))
286
 
 
287
 
            file_id = gen_file_id(f)
288
 
            inv.add_path(f, kind=kind, file_id=file_id)
289
 
 
 
231
            fullpath = os.path.normpath(self._rel(f))
 
232
 
 
233
            if isfile(fullpath):
 
234
                kind = 'file'
 
235
            elif isdir(fullpath):
 
236
                kind = 'directory'
 
237
            else:
 
238
                bailout('cannot add: not a regular file or directory: %s' % quotefn(f))
 
239
 
 
240
            if len(fp) > 1:
 
241
                parent_name = joinpath(fp[:-1])
 
242
                mutter("lookup parent %r" % parent_name)
 
243
                parent_id = inv.path2id(parent_name)
 
244
                if parent_id == None:
 
245
                    bailout("cannot add: parent %r is not versioned"
 
246
                            % joinpath(fp[:-1]))
 
247
            else:
 
248
                parent_id = None
 
249
 
 
250
            file_id = _gen_file_id(fp[-1])
 
251
            inv.add(InventoryEntry(file_id, fp[-1], kind=kind, parent_id=parent_id))
290
252
            if verbose:
291
253
                show_status('A', kind, quotefn(f))
292
254
                
293
 
            mutter("add file %s file_id:{%s} kind=%r" % (f, file_id, kind))
294
 
            
 
255
            mutter("add file %s file_id:{%s} kind=%r parent_id={%s}"
 
256
                   % (f, file_id, kind, parent_id))
295
257
        self._write_inventory(inv)
296
258
 
297
259
 
338
300
        if isinstance(files, types.StringTypes):
339
301
            files = [files]
340
302
        
341
 
        tree = self.working_tree()
342
 
        inv = tree.inventory
 
303
        inv = self.read_working_inventory()
343
304
 
344
305
        # do this before any modifications
345
306
        for f in files:
348
309
                bailout("cannot remove unversioned file %s" % quotefn(f))
349
310
            mutter("remove inventory entry %s {%s}" % (quotefn(f), fid))
350
311
            if verbose:
351
 
                # having remove it, it must be either ignored or unknown
352
 
                if tree.is_ignored(f):
353
 
                    new_status = 'I'
354
 
                else:
355
 
                    new_status = '?'
356
 
                show_status(new_status, inv[fid].kind, quotefn(f))
 
312
                show_status('D', inv[fid].kind, quotefn(f))
357
313
            del inv[fid]
358
314
 
359
315
        self._write_inventory(inv)
426
382
 
427
383
            entry = entry.copy()
428
384
 
429
 
            p = self.abspath(path)
 
385
            p = self._rel(path)
430
386
            file_id = entry.file_id
431
387
            mutter('commit prep file %s, id %r ' % (p, file_id))
432
388
 
472
428
                           entry.text_id)
473
429
                    
474
430
                else:
475
 
                    entry.text_id = gen_file_id(entry.name)
 
431
                    entry.text_id = _gen_file_id(entry.name)
476
432
                    self.text_store.add(content, entry.text_id)
477
433
                    mutter('    stored with text_id {%s}' % entry.text_id)
478
434
                    if verbose:
707
663
        A       foo
708
664
        >>> b.commit("add foo")
709
665
        >>> b.show_status()
710
 
        >>> os.unlink(b.abspath('foo'))
 
666
        >>> os.unlink(b._rel('foo'))
711
667
        >>> b.show_status()
712
668
        D       foo
713
669
        
794
750
        ## mutter('check %r for control file' % ((head, tail), ))
795
751
        if tail == bzrlib.BZRDIR:
796
752
            return True
797
 
        if filename == head:
798
 
            break
799
753
        filename = head
800
754
    return False
801
755
 
808
762
    return s
809
763
 
810
764
 
811
 
def gen_file_id(name):
 
765
def _gen_file_id(name):
812
766
    """Return new file id.
813
767
 
814
768
    This should probably generate proper UUIDs, but for the moment we
815
769
    cope with just randomness because running uuidgen every time is
816
770
    slow."""
817
 
    idx = name.rfind('/')
818
 
    if idx != -1:
819
 
        name = name[idx+1 : ]
820
 
 
821
 
    name = name.lstrip('.')
822
 
 
 
771
    assert '/' not in name
 
772
    while name[0] == '.':
 
773
        name = name[1:]
823
774
    s = hexlify(rand_bytes(8))
824
775
    return '-'.join((name, compact_date(time.time()), s))
825
776