/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
453 by Martin Pool
- Split WorkingTree into its own file
1
# Copyright (C) 2005 Canonical Ltd
2
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
1185.16.72 by Martin Pool
[merge] from robert and fix up tests
17
"""WorkingTree object and friends.
18
19
A WorkingTree represents the editable working copy of a branch.
20
Operations which represent the WorkingTree are also done here, 
21
such as renaming or adding files.  The WorkingTree has an inventory 
22
which is updated by these operations.  A commit produces a 
23
new revision based on the workingtree and its inventory.
24
25
At the moment every WorkingTree has its own branch.  Remote
26
WorkingTrees aren't supported.
27
28
To get a WorkingTree, call Branch.working_tree():
29
"""
30
31
32
# TODO: Don't allow WorkingTrees to be constructed for remote branches if 
33
# they don't work.
453 by Martin Pool
- Split WorkingTree into its own file
34
956 by Martin Pool
doc
35
# FIXME: I don't know if writing out the cache from the destructor is really a
1185.16.72 by Martin Pool
[merge] from robert and fix up tests
36
# good idea, because destructors are considered poor taste in Python, and it's
37
# not predictable when it will be written out.
38
39
# TODO: Give the workingtree sole responsibility for the working inventory;
40
# remove the variable and references to it from the branch.  This may require
41
# updating the commit code so as to update the inventory within the working
42
# copy, and making sure there's only one WorkingTree for any directory on disk.
43
# At the momenthey may alias the inventory and have old copies of it in memory.
956 by Martin Pool
doc
44
1508.1.8 by Robert Collins
move move() from Branch to WorkingTree.
45
from copy import deepcopy
453 by Martin Pool
- Split WorkingTree into its own file
46
import os
1398 by Robert Collins
integrate in Gustavos x-bit patch
47
import stat
1140 by Martin Pool
- lift out import statements within WorkingTree
48
import fnmatch
1457.1.1 by Robert Collins
rather than getting the branch inventory, WorkingTree can use the whole Branch, or make its own.
49
 
1508.1.5 by Robert Collins
Move add from Branch to WorkingTree.
50
from bzrlib.branch import (Branch,
51
                           is_control_file,
52
                           needs_read_lock,
53
                           needs_write_lock,
54
                           quotefn)
55
from bzrlib.errors import (BzrCheckError,
1508.1.7 by Robert Collins
Move rename_one from Branch to WorkingTree. (Robert Collins).
56
                           BzrError,
1508.1.5 by Robert Collins
Move add from Branch to WorkingTree.
57
                           DivergedBranches,
1185.33.59 by Martin Pool
[patch] keep a cached basis inventory (Johan Rydberg)
58
                           WeaveRevisionNotPresent,
1508.1.5 by Robert Collins
Move add from Branch to WorkingTree.
59
                           NotBranchError,
60
                           NotVersionedError)
61
from bzrlib.inventory import InventoryEntry
1457.1.11 by Robert Collins
Move _write_inventory to WorkingTree.
62
from bzrlib.osutils import (appendpath,
1508.1.5 by Robert Collins
Move add from Branch to WorkingTree.
63
                            compact_date,
1457.1.11 by Robert Collins
Move _write_inventory to WorkingTree.
64
                            file_kind,
65
                            isdir,
66
                            pumpfile,
67
                            splitpath,
1508.1.5 by Robert Collins
Move add from Branch to WorkingTree.
68
                            rand_bytes,
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
69
                            realpath,
1508.1.7 by Robert Collins
Move rename_one from Branch to WorkingTree. (Robert Collins).
70
                            relpath,
71
                            rename)
1185.33.92 by Martin Pool
[patch] fix for 'bzr rm -v' (Wouter van Heyst)
72
from bzrlib.textui import show_status
1508.1.5 by Robert Collins
Move add from Branch to WorkingTree.
73
import bzrlib.tree
1140 by Martin Pool
- lift out import statements within WorkingTree
74
from bzrlib.trace import mutter
1497 by Robert Collins
Move Branch.read_working_inventory to WorkingTree.
75
import bzrlib.xml5
453 by Martin Pool
- Split WorkingTree into its own file
76
1465 by Robert Collins
Bugfix the new pull --clobber to not generate spurious conflicts.
77
1508.1.5 by Robert Collins
Move add from Branch to WorkingTree.
78
def gen_file_id(name):
79
    """Return new file id.
80
81
    This should probably generate proper UUIDs, but for the moment we
82
    cope with just randomness because running uuidgen every time is
83
    slow."""
84
    import re
85
    from binascii import hexlify
86
    from time import time
87
88
    # get last component
89
    idx = name.rfind('/')
90
    if idx != -1:
91
        name = name[idx+1 : ]
92
    idx = name.rfind('\\')
93
    if idx != -1:
94
        name = name[idx+1 : ]
95
96
    # make it not a hidden file
97
    name = name.lstrip('.')
98
99
    # remove any wierd characters; we don't escape them but rather
100
    # just pull them out
101
    name = re.sub(r'[^\w.]', '', name)
102
103
    s = hexlify(rand_bytes(8))
104
    return '-'.join((name, compact_date(time()), s))
105
106
107
def gen_root_id():
108
    """Return a new tree-root file id."""
109
    return gen_file_id('TREE_ROOT')
110
111
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
112
class TreeEntry(object):
113
    """An entry that implements the minium interface used by commands.
114
115
    This needs further inspection, it may be better to have 
116
    InventoryEntries without ids - though that seems wrong. For now,
117
    this is a parallel hierarchy to InventoryEntry, and needs to become
118
    one of several things: decorates to that hierarchy, children of, or
119
    parents of it.
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
120
    Another note is that these objects are currently only used when there is
121
    no InventoryEntry available - i.e. for unversioned objects.
122
    Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
123
    """
124
 
125
    def __eq__(self, other):
126
        # yes, this us ugly, TODO: best practice __eq__ style.
127
        return (isinstance(other, TreeEntry)
128
                and other.__class__ == self.__class__)
129
 
130
    def kind_character(self):
131
        return "???"
132
133
134
class TreeDirectory(TreeEntry):
135
    """See TreeEntry. This is a directory in a working tree."""
136
137
    def __eq__(self, other):
138
        return (isinstance(other, TreeDirectory)
139
                and other.__class__ == self.__class__)
140
141
    def kind_character(self):
142
        return "/"
143
144
145
class TreeFile(TreeEntry):
146
    """See TreeEntry. This is a regular file in a working tree."""
147
148
    def __eq__(self, other):
149
        return (isinstance(other, TreeFile)
150
                and other.__class__ == self.__class__)
151
152
    def kind_character(self):
153
        return ''
154
155
156
class TreeLink(TreeEntry):
157
    """See TreeEntry. This is a symlink in a working tree."""
158
159
    def __eq__(self, other):
160
        return (isinstance(other, TreeLink)
161
                and other.__class__ == self.__class__)
162
163
    def kind_character(self):
164
        return ''
165
166
453 by Martin Pool
- Split WorkingTree into its own file
167
class WorkingTree(bzrlib.tree.Tree):
168
    """Working copy tree.
169
170
    The inventory is held in the `Branch` working-inventory, and the
171
    files are in a directory on disk.
172
173
    It is possible for a `WorkingTree` to have a filename which is
174
    not listed in the Inventory and vice versa.
175
    """
1442.1.65 by Robert Collins
Branch.remove has been moved to WorkingTree.
176
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
177
    def __init__(self, basedir=u'.', branch=None):
1457.1.1 by Robert Collins
rather than getting the branch inventory, WorkingTree can use the whole Branch, or make its own.
178
        """Construct a WorkingTree for basedir.
179
180
        If the branch is not supplied, it is opened automatically.
181
        If the branch is supplied, it must be the branch for this basedir.
182
        (branch.base is not cross checked, because for remote branches that
183
        would be meaningless).
184
        """
866 by Martin Pool
- use new path-based hashcache for WorkingTree- squash mtime/ctime to whole seconds- update and if necessary write out hashcache when WorkingTree object is created.
185
        from bzrlib.hashcache import HashCache
186
        from bzrlib.trace import note, mutter
1185.16.72 by Martin Pool
[merge] from robert and fix up tests
187
        assert isinstance(basedir, basestring), \
188
            "base directory %r is not a string" % basedir
1457.1.1 by Robert Collins
rather than getting the branch inventory, WorkingTree can use the whole Branch, or make its own.
189
        if branch is None:
190
            branch = Branch.open(basedir)
1185.16.72 by Martin Pool
[merge] from robert and fix up tests
191
        assert isinstance(branch, Branch), \
192
            "branch %r is not a Branch" % branch
1457.1.1 by Robert Collins
rather than getting the branch inventory, WorkingTree can use the whole Branch, or make its own.
193
        self.branch = branch
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
194
        self.basedir = realpath(basedir)
195
196
        self._set_inventory(self.read_working_inventory())
866 by Martin Pool
- use new path-based hashcache for WorkingTree- squash mtime/ctime to whole seconds- update and if necessary write out hashcache when WorkingTree object is created.
197
198
        # update the whole cache up front and write to disk if anything changed;
199
        # in the future we might want to do this more selectively
1467 by Robert Collins
WorkingTree.__del__ has been removed.
200
        # two possible ways offer themselves : in self._unlock, write the cache
201
        # if needed, or, when the cache sees a change, append it to the hash
202
        # cache file, and have the parser take the most recent entry for a
203
        # given path only.
866 by Martin Pool
- use new path-based hashcache for WorkingTree- squash mtime/ctime to whole seconds- update and if necessary write out hashcache when WorkingTree object is created.
204
        hc = self._hashcache = HashCache(basedir)
205
        hc.read()
954 by Martin Pool
- separate out code that just scans the hash cache to find files that are possibly
206
        hc.scan()
866 by Martin Pool
- use new path-based hashcache for WorkingTree- squash mtime/ctime to whole seconds- update and if necessary write out hashcache when WorkingTree object is created.
207
208
        if hc.needs_write:
209
            mutter("write hc")
210
            hc.write()
453 by Martin Pool
- Split WorkingTree into its own file
211
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
212
    def _set_inventory(self, inv):
213
        self._inventory = inv
214
        self.path2id = self._inventory.path2id
215
1508.1.1 by Robert Collins
Provide a open_containing for WorkingTree.
216
    @staticmethod
217
    def open_containing(path=None):
218
        """Open an existing working tree which has its root about path.
219
        
220
        This probes for a working tree at path and searches upwards from there.
221
222
        Basically we keep looking up until we find the control directory or
223
        run into /.  If there isn't one, raises NotBranchError.
224
        TODO: give this a new exception.
225
        If there is one, it is returned, along with the unused portion of path.
226
        """
227
        if path is None:
228
            path = os.getcwdu()
1508.1.3 by Robert Collins
Do not consider urls to be relative paths within working trees.
229
        else:
230
            # sanity check.
231
            if path.find('://') != -1:
232
                raise NotBranchError(path=path)
1508.1.2 by Robert Collins
Use abspath not realpath in WorkingTree.open_containing, to avoid symlink resolution lies.
233
        path = os.path.abspath(path)
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
234
        tail = u''
1508.1.1 by Robert Collins
Provide a open_containing for WorkingTree.
235
        while True:
236
            try:
237
                return WorkingTree(path), tail
238
            except NotBranchError:
239
                pass
240
            if tail:
241
                tail = os.path.join(os.path.basename(path), tail)
242
            else:
243
                tail = os.path.basename(path)
244
            path = os.path.dirname(path)
245
            # FIXME: top in windows is indicated how ???
246
            if path == os.path.sep:
247
                # reached the root, whatever that may be
248
                raise NotBranchError(path=path)
249
462 by Martin Pool
- New form 'file_id in tree' to check if the file is present
250
    def __iter__(self):
251
        """Iterate through file_ids for this tree.
252
253
        file_ids are in a WorkingTree if they are in the working inventory
254
        and the working file exists.
255
        """
256
        inv = self._inventory
866 by Martin Pool
- use new path-based hashcache for WorkingTree- squash mtime/ctime to whole seconds- update and if necessary write out hashcache when WorkingTree object is created.
257
        for path, ie in inv.iter_entries():
1092.2.6 by Robert Collins
symlink support updated to work
258
            if bzrlib.osutils.lexists(self.abspath(path)):
866 by Martin Pool
- use new path-based hashcache for WorkingTree- squash mtime/ctime to whole seconds- update and if necessary write out hashcache when WorkingTree object is created.
259
                yield ie.file_id
462 by Martin Pool
- New form 'file_id in tree' to check if the file is present
260
453 by Martin Pool
- Split WorkingTree into its own file
261
    def __repr__(self):
262
        return "<%s of %s>" % (self.__class__.__name__,
954 by Martin Pool
- separate out code that just scans the hash cache to find files that are possibly
263
                               getattr(self, 'basedir', None))
453 by Martin Pool
- Split WorkingTree into its own file
264
265
    def abspath(self, filename):
266
        return os.path.join(self.basedir, filename)
267
1457.1.3 by Robert Collins
make Branch.relpath delegate to the working tree.
268
    def relpath(self, abspath):
269
        """Return the local path portion from a given absolute path."""
270
        return relpath(self.basedir, abspath)
271
453 by Martin Pool
- Split WorkingTree into its own file
272
    def has_filename(self, filename):
1092.2.6 by Robert Collins
symlink support updated to work
273
        return bzrlib.osutils.lexists(self.abspath(filename))
453 by Martin Pool
- Split WorkingTree into its own file
274
275
    def get_file(self, file_id):
276
        return self.get_file_byname(self.id2path(file_id))
277
278
    def get_file_byname(self, filename):
279
        return file(self.abspath(filename), 'rb')
280
1497 by Robert Collins
Move Branch.read_working_inventory to WorkingTree.
281
    def get_root_id(self):
282
        """Return the id of this trees root"""
283
        inv = self.read_working_inventory()
284
        return inv.root.file_id
285
        
453 by Martin Pool
- Split WorkingTree into its own file
286
    def _get_store_filename(self, file_id):
1508.1.1 by Robert Collins
Provide a open_containing for WorkingTree.
287
        ## XXX: badly named; this is not in the store at all
453 by Martin Pool
- Split WorkingTree into its own file
288
        return self.abspath(self.id2path(file_id))
289
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
290
    @needs_write_lock
291
    def commit(self, *args, **kw):
292
        from bzrlib.commit import Commit
293
        Commit().commit(self.branch, *args, **kw)
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
294
        self._set_inventory(self.read_working_inventory())
1248 by Martin Pool
- new weave based cleanup [broken]
295
296
    def id2abspath(self, file_id):
297
        return self.abspath(self.id2path(file_id))
298
1185.12.39 by abentley
Propogated has_or_had_id to Tree
299
    def has_id(self, file_id):
453 by Martin Pool
- Split WorkingTree into its own file
300
        # files that have been deleted are excluded
1185.12.39 by abentley
Propogated has_or_had_id to Tree
301
        inv = self._inventory
866 by Martin Pool
- use new path-based hashcache for WorkingTree- squash mtime/ctime to whole seconds- update and if necessary write out hashcache when WorkingTree object is created.
302
        if not inv.has_id(file_id):
453 by Martin Pool
- Split WorkingTree into its own file
303
            return False
866 by Martin Pool
- use new path-based hashcache for WorkingTree- squash mtime/ctime to whole seconds- update and if necessary write out hashcache when WorkingTree object is created.
304
        path = inv.id2path(file_id)
1092.2.6 by Robert Collins
symlink support updated to work
305
        return bzrlib.osutils.lexists(self.abspath(path))
462 by Martin Pool
- New form 'file_id in tree' to check if the file is present
306
1185.12.39 by abentley
Propogated has_or_had_id to Tree
307
    def has_or_had_id(self, file_id):
308
        if file_id == self.inventory.root.file_id:
309
            return True
310
        return self.inventory.has_id(file_id)
462 by Martin Pool
- New form 'file_id in tree' to check if the file is present
311
312
    __contains__ = has_id
313
453 by Martin Pool
- Split WorkingTree into its own file
314
    def get_file_size(self, file_id):
1248 by Martin Pool
- new weave based cleanup [broken]
315
        return os.path.getsize(self.id2abspath(file_id))
453 by Martin Pool
- Split WorkingTree into its own file
316
317
    def get_file_sha1(self, file_id):
866 by Martin Pool
- use new path-based hashcache for WorkingTree- squash mtime/ctime to whole seconds- update and if necessary write out hashcache when WorkingTree object is created.
318
        path = self._inventory.id2path(file_id)
319
        return self._hashcache.get_sha1(path)
453 by Martin Pool
- Split WorkingTree into its own file
320
1398 by Robert Collins
integrate in Gustavos x-bit patch
321
    def is_executable(self, file_id):
322
        if os.name == "nt":
323
            return self._inventory[file_id].executable
324
        else:
325
            path = self._inventory.id2path(file_id)
326
            mode = os.lstat(self.abspath(path)).st_mode
327
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC&mode)
328
1457.1.16 by Robert Collins
Move set_pending_merges to WorkingTree.
329
    @needs_write_lock
1508.1.5 by Robert Collins
Move add from Branch to WorkingTree.
330
    def add(self, files, ids=None):
331
        """Make files versioned.
332
333
        Note that the command line normally calls smart_add instead,
334
        which can automatically recurse.
335
336
        This adds the files to the inventory, so that they will be
337
        recorded by the next commit.
338
339
        files
340
            List of paths to add, relative to the base of the tree.
341
342
        ids
343
            If set, use these instead of automatically generated ids.
344
            Must be the same length as the list of files, but may
345
            contain None for ids that are to be autogenerated.
346
347
        TODO: Perhaps have an option to add the ids even if the files do
348
              not (yet) exist.
349
350
        TODO: Perhaps callback with the ids and paths as they're added.
351
        """
352
        # TODO: Re-adding a file that is removed in the working copy
353
        # should probably put it back with the previous ID.
354
        if isinstance(files, basestring):
355
            assert(ids is None or isinstance(ids, basestring))
356
            files = [files]
357
            if ids is not None:
358
                ids = [ids]
359
360
        if ids is None:
361
            ids = [None] * len(files)
362
        else:
363
            assert(len(ids) == len(files))
364
365
        inv = self.read_working_inventory()
366
        for f,file_id in zip(files, ids):
367
            if is_control_file(f):
368
                raise BzrError("cannot add control file %s" % quotefn(f))
369
370
            fp = splitpath(f)
371
372
            if len(fp) == 0:
373
                raise BzrError("cannot add top-level %r" % f)
374
375
            fullpath = os.path.normpath(self.abspath(f))
376
377
            try:
378
                kind = file_kind(fullpath)
379
            except OSError:
380
                # maybe something better?
381
                raise BzrError('cannot add: not a regular file, symlink or directory: %s' % quotefn(f))
382
383
            if not InventoryEntry.versionable_kind(kind):
384
                raise BzrError('cannot add: not a versionable file ('
385
                               'i.e. regular file, symlink or directory): %s' % quotefn(f))
386
387
            if file_id is None:
388
                file_id = gen_file_id(f)
389
            inv.add_path(f, kind=kind, file_id=file_id)
390
391
            mutter("add file %s file_id:{%s} kind=%r" % (f, file_id, kind))
392
        self._write_inventory(inv)
393
394
    @needs_write_lock
1457.1.15 by Robert Collins
Move add_pending_merge to WorkingTree.
395
    def add_pending_merge(self, *revision_ids):
396
        # TODO: Perhaps should check at this point that the
397
        # history of the revision is actually present?
398
        p = self.pending_merges()
399
        updated = False
400
        for rev_id in revision_ids:
401
            if rev_id in p:
402
                continue
403
            p.append(rev_id)
404
            updated = True
405
        if updated:
1457.1.16 by Robert Collins
Move set_pending_merges to WorkingTree.
406
            self.set_pending_merges(p)
1457.1.15 by Robert Collins
Move add_pending_merge to WorkingTree.
407
1457.1.14 by Robert Collins
Move pending_merges() to WorkingTree.
408
    def pending_merges(self):
409
        """Return a list of pending merges.
410
411
        These are revisions that have been merged into the working
412
        directory but not yet committed.
413
        """
414
        cfn = self.branch._rel_controlfilename('pending-merges')
415
        if not self.branch._transport.has(cfn):
416
            return []
417
        p = []
418
        for l in self.branch.controlfile('pending-merges', 'r').readlines():
419
            p.append(l.rstrip('\n'))
420
        return p
421
1457.1.16 by Robert Collins
Move set_pending_merges to WorkingTree.
422
    @needs_write_lock
423
    def set_pending_merges(self, rev_list):
424
        self.branch.put_controlfile('pending-merges', '\n'.join(rev_list))
425
1092.2.6 by Robert Collins
symlink support updated to work
426
    def get_symlink_target(self, file_id):
1185.15.10 by Scott James Remnant
Fix WorkingTree.get_symlink_target() to read the absolute path of the
427
        return os.readlink(self.id2abspath(file_id))
453 by Martin Pool
- Split WorkingTree into its own file
428
429
    def file_class(self, filename):
430
        if self.path2id(filename):
431
            return 'V'
432
        elif self.is_ignored(filename):
433
            return 'I'
434
        else:
435
            return '?'
436
437
438
    def list_files(self):
439
        """Recursively list all files as (path, class, kind, id).
440
441
        Lists, but does not descend into unversioned directories.
442
443
        This does not include files that have been deleted in this
444
        tree.
445
446
        Skips the control directory.
447
        """
866 by Martin Pool
- use new path-based hashcache for WorkingTree- squash mtime/ctime to whole seconds- update and if necessary write out hashcache when WorkingTree object is created.
448
        inv = self._inventory
453 by Martin Pool
- Split WorkingTree into its own file
449
450
        def descend(from_dir_relpath, from_dir_id, dp):
451
            ls = os.listdir(dp)
452
            ls.sort()
453
            for f in ls:
454
                ## TODO: If we find a subdirectory with its own .bzr
455
                ## directory, then that is a separate tree and we
456
                ## should exclude it.
457
                if bzrlib.BZRDIR == f:
458
                    continue
459
460
                # path within tree
461
                fp = appendpath(from_dir_relpath, f)
462
463
                # absolute path
464
                fap = appendpath(dp, f)
465
                
466
                f_ie = inv.get_child(from_dir_id, f)
467
                if f_ie:
468
                    c = 'V'
469
                elif self.is_ignored(fp):
470
                    c = 'I'
471
                else:
472
                    c = '?'
473
474
                fk = file_kind(fap)
475
476
                if f_ie:
477
                    if f_ie.kind != fk:
478
                        raise BzrCheckError("file %r entered as kind %r id %r, "
479
                                            "now of kind %r"
480
                                            % (fap, f_ie.kind, f_ie.file_id, fk))
481
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
482
                # make a last minute entry
483
                if f_ie:
484
                    entry = f_ie
485
                else:
486
                    if fk == 'directory':
487
                        entry = TreeDirectory()
488
                    elif fk == 'file':
489
                        entry = TreeFile()
490
                    elif fk == 'symlink':
491
                        entry = TreeLink()
492
                    else:
493
                        entry = TreeEntry()
494
                
495
                yield fp, c, fk, (f_ie and f_ie.file_id), entry
453 by Martin Pool
- Split WorkingTree into its own file
496
497
                if fk != 'directory':
498
                    continue
499
500
                if c != 'V':
501
                    # don't descend unversioned directories
502
                    continue
503
                
504
                for ff in descend(fp, f_ie.file_id, fap):
505
                    yield ff
506
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
507
        for f in descend(u'', inv.root.file_id, self.basedir):
453 by Martin Pool
- Split WorkingTree into its own file
508
            yield f
1508.1.7 by Robert Collins
Move rename_one from Branch to WorkingTree. (Robert Collins).
509
510
    @needs_write_lock
1508.1.8 by Robert Collins
move move() from Branch to WorkingTree.
511
    def move(self, from_paths, to_name):
512
        """Rename files.
513
514
        to_name must exist in the inventory.
515
516
        If to_name exists and is a directory, the files are moved into
517
        it, keeping their old names.  
518
519
        Note that to_name is only the last component of the new name;
520
        this doesn't change the directory.
521
522
        This returns a list of (from_path, to_path) pairs for each
523
        entry that is moved.
524
        """
525
        result = []
526
        ## TODO: Option to move IDs only
527
        assert not isinstance(from_paths, basestring)
528
        inv = self.inventory
529
        to_abs = self.abspath(to_name)
530
        if not isdir(to_abs):
531
            raise BzrError("destination %r is not a directory" % to_abs)
532
        if not self.has_filename(to_name):
533
            raise BzrError("destination %r not in working directory" % to_abs)
534
        to_dir_id = inv.path2id(to_name)
535
        if to_dir_id == None and to_name != '':
536
            raise BzrError("destination %r is not a versioned directory" % to_name)
537
        to_dir_ie = inv[to_dir_id]
538
        if to_dir_ie.kind not in ('directory', 'root_directory'):
539
            raise BzrError("destination %r is not a directory" % to_abs)
540
541
        to_idpath = inv.get_idpath(to_dir_id)
542
543
        for f in from_paths:
544
            if not self.has_filename(f):
545
                raise BzrError("%r does not exist in working tree" % f)
546
            f_id = inv.path2id(f)
547
            if f_id == None:
548
                raise BzrError("%r is not versioned" % f)
549
            name_tail = splitpath(f)[-1]
550
            dest_path = appendpath(to_name, name_tail)
551
            if self.has_filename(dest_path):
552
                raise BzrError("destination %r already exists" % dest_path)
553
            if f_id in to_idpath:
554
                raise BzrError("can't move %r to a subdirectory of itself" % f)
555
556
        # OK, so there's a race here, it's possible that someone will
557
        # create a file in this interval and then the rename might be
558
        # left half-done.  But we should have caught most problems.
559
        orig_inv = deepcopy(self.inventory)
560
        try:
561
            for f in from_paths:
562
                name_tail = splitpath(f)[-1]
563
                dest_path = appendpath(to_name, name_tail)
564
                result.append((f, dest_path))
565
                inv.rename(inv.path2id(f), to_dir_id, name_tail)
566
                try:
567
                    rename(self.abspath(f), self.abspath(dest_path))
568
                except OSError, e:
569
                    raise BzrError("failed to rename %r to %r: %s" %
570
                                   (f, dest_path, e[1]),
571
                            ["rename rolled back"])
572
        except:
573
            # restore the inventory on error
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
574
            self._set_inventory(orig_inv)
1508.1.8 by Robert Collins
move move() from Branch to WorkingTree.
575
            raise
576
        self._write_inventory(inv)
577
        return result
578
579
    @needs_write_lock
1508.1.7 by Robert Collins
Move rename_one from Branch to WorkingTree. (Robert Collins).
580
    def rename_one(self, from_rel, to_rel):
581
        """Rename one file.
582
583
        This can change the directory or the filename or both.
584
        """
585
        inv = self.inventory
586
        if not self.has_filename(from_rel):
587
            raise BzrError("can't rename: old working file %r does not exist" % from_rel)
588
        if self.has_filename(to_rel):
589
            raise BzrError("can't rename: new working file %r already exists" % to_rel)
590
591
        file_id = inv.path2id(from_rel)
592
        if file_id == None:
593
            raise BzrError("can't rename: old name %r is not versioned" % from_rel)
594
595
        entry = inv[file_id]
596
        from_parent = entry.parent_id
597
        from_name = entry.name
598
        
599
        if inv.path2id(to_rel):
600
            raise BzrError("can't rename: new name %r is already versioned" % to_rel)
601
602
        to_dir, to_tail = os.path.split(to_rel)
603
        to_dir_id = inv.path2id(to_dir)
604
        if to_dir_id == None and to_dir != '':
605
            raise BzrError("can't determine destination directory id for %r" % to_dir)
606
607
        mutter("rename_one:")
608
        mutter("  file_id    {%s}" % file_id)
609
        mutter("  from_rel   %r" % from_rel)
610
        mutter("  to_rel     %r" % to_rel)
611
        mutter("  to_dir     %r" % to_dir)
612
        mutter("  to_dir_id  {%s}" % to_dir_id)
613
614
        inv.rename(file_id, to_dir_id, to_tail)
615
616
        from_abs = self.abspath(from_rel)
617
        to_abs = self.abspath(to_rel)
618
        try:
619
            rename(from_abs, to_abs)
620
        except OSError, e:
621
            inv.rename(file_id, from_parent, from_name)
622
            raise BzrError("failed to rename %r to %r: %s"
623
                    % (from_abs, to_abs, e[1]),
624
                    ["rename rolled back"])
625
        self._write_inventory(inv)
626
627
    @needs_read_lock
453 by Martin Pool
- Split WorkingTree into its own file
628
    def unknowns(self):
1508.1.6 by Robert Collins
Move Branch.unknowns() to WorkingTree.
629
        """Return all unknown files.
630
631
        These are files in the working directory that are not versioned or
632
        control files or ignored.
633
        
634
        >>> from bzrlib.branch import ScratchBranch
635
        >>> b = ScratchBranch(files=['foo', 'foo~'])
636
        >>> tree = WorkingTree(b.base, b)
637
        >>> map(str, tree.unknowns())
638
        ['foo']
639
        >>> tree.add('foo')
640
        >>> list(b.unknowns())
641
        []
642
        >>> tree.remove('foo')
643
        >>> list(b.unknowns())
644
        [u'foo']
645
        """
453 by Martin Pool
- Split WorkingTree into its own file
646
        for subp in self.extras():
647
            if not self.is_ignored(subp):
648
                yield subp
649
1185.14.6 by Aaron Bentley
Made iter_conflicts a WorkingTree method
650
    def iter_conflicts(self):
651
        conflicted = set()
652
        for path in (s[0] for s in self.list_files()):
653
            stem = get_conflicted_stem(path)
654
            if stem is None:
655
                continue
656
            if stem not in conflicted:
657
                conflicted.add(stem)
658
                yield stem
453 by Martin Pool
- Split WorkingTree into its own file
659
1442.1.67 by Robert Collins
Factor out the guts of 'pull' from the command into WorkingTree.pull().
660
    @needs_write_lock
1490 by Robert Collins
Implement a 'bzr push' command, with saved locations; update diff to return 1.
661
    def pull(self, source, overwrite=False):
1465 by Robert Collins
Bugfix the new pull --clobber to not generate spurious conflicts.
662
        from bzrlib.merge import merge_inner
1442.1.67 by Robert Collins
Factor out the guts of 'pull' from the command into WorkingTree.pull().
663
        source.lock_read()
664
        try:
665
            old_revision_history = self.branch.revision_history()
1185.33.44 by Martin Pool
[patch] show number of revisions pushed/pulled/merged (Robey Pointer)
666
            count = self.branch.pull(source, overwrite)
1442.1.67 by Robert Collins
Factor out the guts of 'pull' from the command into WorkingTree.pull().
667
            new_revision_history = self.branch.revision_history()
668
            if new_revision_history != old_revision_history:
1465 by Robert Collins
Bugfix the new pull --clobber to not generate spurious conflicts.
669
                if len(old_revision_history):
670
                    other_revision = old_revision_history[-1]
671
                else:
672
                    other_revision = None
673
                merge_inner(self.branch,
674
                            self.branch.basis_tree(), 
675
                            self.branch.revision_tree(other_revision))
1185.33.44 by Martin Pool
[patch] show number of revisions pushed/pulled/merged (Robey Pointer)
676
            return count
1442.1.67 by Robert Collins
Factor out the guts of 'pull' from the command into WorkingTree.pull().
677
        finally:
678
            source.unlock()
679
453 by Martin Pool
- Split WorkingTree into its own file
680
    def extras(self):
681
        """Yield all unknown files in this WorkingTree.
682
683
        If there are any unknown directories then only the directory is
684
        returned, not all its children.  But if there are unknown files
685
        under a versioned subdirectory, they are returned.
686
687
        Currently returned depth-first, sorted by name within directories.
688
        """
689
        ## TODO: Work from given directory downwards
690
        for path, dir_entry in self.inventory.directories():
1185.31.4 by John Arbash Meinel
Fixing mutter() calls to not have to do string processing.
691
            mutter("search for unknowns in %r", path)
453 by Martin Pool
- Split WorkingTree into its own file
692
            dirabs = self.abspath(path)
693
            if not isdir(dirabs):
694
                # e.g. directory deleted
695
                continue
696
697
            fl = []
698
            for subf in os.listdir(dirabs):
699
                if (subf != '.bzr'
700
                    and (subf not in dir_entry.children)):
701
                    fl.append(subf)
702
            
703
            fl.sort()
704
            for subf in fl:
705
                subp = appendpath(path, subf)
706
                yield subp
707
708
709
    def ignored_files(self):
710
        """Yield list of PATH, IGNORE_PATTERN"""
711
        for subp in self.extras():
712
            pat = self.is_ignored(subp)
713
            if pat != None:
714
                yield subp, pat
715
716
717
    def get_ignore_list(self):
718
        """Return list of ignore patterns.
719
720
        Cached in the Tree object after the first call.
721
        """
722
        if hasattr(self, '_ignorelist'):
723
            return self._ignorelist
724
725
        l = bzrlib.DEFAULT_IGNORE[:]
726
        if self.has_filename(bzrlib.IGNORE_FILENAME):
727
            f = self.get_file_byname(bzrlib.IGNORE_FILENAME)
728
            l.extend([line.rstrip("\n\r") for line in f.readlines()])
729
        self._ignorelist = l
730
        return l
731
732
733
    def is_ignored(self, filename):
734
        r"""Check whether the filename matches an ignore pattern.
735
736
        Patterns containing '/' or '\' need to match the whole path;
737
        others match against only the last component.
738
739
        If the file is ignored, returns the pattern which caused it to
740
        be ignored, otherwise None.  So this can simply be used as a
741
        boolean if desired."""
742
743
        # TODO: Use '**' to match directories, and other extended
744
        # globbing stuff from cvs/rsync.
745
746
        # XXX: fnmatch is actually not quite what we want: it's only
747
        # approximately the same as real Unix fnmatch, and doesn't
748
        # treat dotfiles correctly and allows * to match /.
749
        # Eventually it should be replaced with something more
750
        # accurate.
751
        
752
        for pat in self.get_ignore_list():
753
            if '/' in pat or '\\' in pat:
754
                
755
                # as a special case, you can put ./ at the start of a
756
                # pattern; this is good to match in the top-level
757
                # only;
758
                
759
                if (pat[:2] == './') or (pat[:2] == '.\\'):
760
                    newpat = pat[2:]
761
                else:
762
                    newpat = pat
763
                if fnmatch.fnmatchcase(filename, newpat):
764
                    return pat
765
            else:
766
                if fnmatch.fnmatchcase(splitpath(filename)[-1], pat):
767
                    return pat
768
        else:
769
            return None
1185.14.6 by Aaron Bentley
Made iter_conflicts a WorkingTree method
770
1185.12.28 by Aaron Bentley
Removed use of readonly path for executability test
771
    def kind(self, file_id):
772
        return file_kind(self.id2abspath(file_id))
773
1442.1.65 by Robert Collins
Branch.remove has been moved to WorkingTree.
774
    def lock_read(self):
775
        """See Branch.lock_read, and WorkingTree.unlock."""
776
        return self.branch.lock_read()
777
778
    def lock_write(self):
779
        """See Branch.lock_write, and WorkingTree.unlock."""
780
        return self.branch.lock_write()
781
1185.33.59 by Martin Pool
[patch] keep a cached basis inventory (Johan Rydberg)
782
    def _basis_inventory_name(self, revision_id):
783
        return 'basis-inventory.%s' % revision_id
784
785
    def set_last_revision(self, new_revision, old_revision=None):
786
        if old_revision:
787
            try:
788
                path = self._basis_inventory_name(old_revision)
789
                path = self.branch._rel_controlfilename(path)
790
                self.branch._transport.delete(path)
791
            except:
792
                pass
793
        try:
794
            xml = self.branch.get_inventory_xml(new_revision)
795
            path = self._basis_inventory_name(new_revision)
796
            self.branch.put_controlfile(path, xml)
797
        except WeaveRevisionNotPresent:
798
            pass
799
800
    def read_basis_inventory(self, revision_id):
801
        """Read the cached basis inventory."""
802
        path = self._basis_inventory_name(revision_id)
803
        return self.branch.controlfile(path, 'r').read()
804
        
1497 by Robert Collins
Move Branch.read_working_inventory to WorkingTree.
805
    @needs_read_lock
806
    def read_working_inventory(self):
807
        """Read the working inventory."""
808
        # ElementTree does its own conversion from UTF-8, so open in
809
        # binary.
810
        f = self.branch.controlfile('inventory', 'rb')
811
        return bzrlib.xml5.serializer_v5.read_inventory(f)
812
1442.1.65 by Robert Collins
Branch.remove has been moved to WorkingTree.
813
    @needs_write_lock
814
    def remove(self, files, verbose=False):
815
        """Remove nominated files from the working inventory..
816
817
        This does not remove their text.  This does not run on XXX on what? RBC
818
819
        TODO: Refuse to remove modified files unless --force is given?
820
821
        TODO: Do something useful with directories.
822
823
        TODO: Should this remove the text or not?  Tough call; not
824
        removing may be useful and the user can just use use rm, and
825
        is the opposite of add.  Removing it is consistent with most
826
        other tools.  Maybe an option.
827
        """
828
        ## TODO: Normalize names
829
        ## TODO: Remove nested loops; better scalability
830
        if isinstance(files, basestring):
831
            files = [files]
832
833
        inv = self.inventory
834
835
        # do this before any modifications
836
        for f in files:
837
            fid = inv.path2id(f)
838
            if not fid:
1185.16.72 by Martin Pool
[merge] from robert and fix up tests
839
                # TODO: Perhaps make this just a warning, and continue?
840
                # This tends to happen when 
841
                raise NotVersionedError(path=f)
1185.31.4 by John Arbash Meinel
Fixing mutter() calls to not have to do string processing.
842
            mutter("remove inventory entry %s {%s}", quotefn(f), fid)
1442.1.65 by Robert Collins
Branch.remove has been moved to WorkingTree.
843
            if verbose:
844
                # having remove it, it must be either ignored or unknown
845
                if self.is_ignored(f):
846
                    new_status = 'I'
847
                else:
848
                    new_status = '?'
849
                show_status(new_status, inv[fid].kind, quotefn(f))
850
            del inv[fid]
851
1457.1.11 by Robert Collins
Move _write_inventory to WorkingTree.
852
        self._write_inventory(inv)
1442.1.65 by Robert Collins
Branch.remove has been moved to WorkingTree.
853
1497 by Robert Collins
Move Branch.read_working_inventory to WorkingTree.
854
    @needs_write_lock
1501 by Robert Collins
Move revert from Branch to WorkingTree.
855
    def revert(self, filenames, old_tree=None, backups=True):
1457.1.8 by Robert Collins
Replace the WorkingTree.revert method algorithm with a call to merge_inner.
856
        from bzrlib.merge import merge_inner
1501 by Robert Collins
Move revert from Branch to WorkingTree.
857
        if old_tree is None:
858
            old_tree = self.branch.basis_tree()
1457.1.8 by Robert Collins
Replace the WorkingTree.revert method algorithm with a call to merge_inner.
859
        merge_inner(self.branch, old_tree,
860
                    self, ignore_zero=True,
861
                    backup_files=backups, 
862
                    interesting_files=filenames)
863
        if not len(filenames):
1457.1.16 by Robert Collins
Move set_pending_merges to WorkingTree.
864
            self.set_pending_merges([])
1501 by Robert Collins
Move revert from Branch to WorkingTree.
865
866
    @needs_write_lock
1497 by Robert Collins
Move Branch.read_working_inventory to WorkingTree.
867
    def set_inventory(self, new_inventory_list):
868
        from bzrlib.inventory import (Inventory,
869
                                      InventoryDirectory,
870
                                      InventoryEntry,
871
                                      InventoryFile,
872
                                      InventoryLink)
873
        inv = Inventory(self.get_root_id())
874
        for path, file_id, parent, kind in new_inventory_list:
875
            name = os.path.basename(path)
876
            if name == "":
877
                continue
878
            # fixme, there should be a factory function inv,add_?? 
879
            if kind == 'directory':
880
                inv.add(InventoryDirectory(file_id, name, parent))
881
            elif kind == 'file':
882
                inv.add(InventoryFile(file_id, name, parent))
883
            elif kind == 'symlink':
884
                inv.add(InventoryLink(file_id, name, parent))
885
            else:
886
                raise BzrError("unknown kind %r" % kind)
1457.1.11 by Robert Collins
Move _write_inventory to WorkingTree.
887
        self._write_inventory(inv)
1497 by Robert Collins
Move Branch.read_working_inventory to WorkingTree.
888
1457.1.10 by Robert Collins
Move set_root_id to WorkingTree.
889
    @needs_write_lock
890
    def set_root_id(self, file_id):
891
        """Set the root id for this tree."""
892
        inv = self.read_working_inventory()
893
        orig_root_id = inv.root.file_id
894
        del inv._byid[inv.root.file_id]
895
        inv.root.file_id = file_id
896
        inv._byid[inv.root.file_id] = inv.root
897
        for fid in inv:
898
            entry = inv[fid]
899
            if entry.parent_id in (None, orig_root_id):
900
                entry.parent_id = inv.root.file_id
1457.1.11 by Robert Collins
Move _write_inventory to WorkingTree.
901
        self._write_inventory(inv)
1457.1.10 by Robert Collins
Move set_root_id to WorkingTree.
902
1442.1.65 by Robert Collins
Branch.remove has been moved to WorkingTree.
903
    def unlock(self):
904
        """See Branch.unlock.
905
        
906
        WorkingTree locking just uses the Branch locking facilities.
907
        This is current because all working trees have an embedded branch
908
        within them. IF in the future, we were to make branch data shareable
909
        between multiple working trees, i.e. via shared storage, then we 
910
        would probably want to lock both the local tree, and the branch.
911
        """
912
        return self.branch.unlock()
913
1457.1.11 by Robert Collins
Move _write_inventory to WorkingTree.
914
    @needs_write_lock
915
    def _write_inventory(self, inv):
916
        """Write inventory as the current inventory."""
917
        from cStringIO import StringIO
918
        from bzrlib.atomicfile import AtomicFile
919
        sio = StringIO()
920
        bzrlib.xml5.serializer_v5.write_inventory(inv, sio)
921
        sio.seek(0)
922
        f = AtomicFile(self.branch.controlfilename('inventory'))
923
        try:
924
            pumpfile(sio, f)
925
            f.commit()
926
        finally:
927
            f.close()
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
928
        self._set_inventory(inv)
1457.1.11 by Robert Collins
Move _write_inventory to WorkingTree.
929
        mutter('wrote working inventory')
930
            
1442.1.65 by Robert Collins
Branch.remove has been moved to WorkingTree.
931
1185.14.6 by Aaron Bentley
Made iter_conflicts a WorkingTree method
932
CONFLICT_SUFFIXES = ('.THIS', '.BASE', '.OTHER')
933
def get_conflicted_stem(path):
934
    for suffix in CONFLICT_SUFFIXES:
935
        if path.endswith(suffix):
936
            return path[:-len(suffix)]