~bzr-pqm/bzr/bzr.dev

1911.3.1 by John Arbash Meinel
Updated smart_add so that the AddAction can return a custom id.
1
# Copyright (C) 2005, 2006 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
17
from cStringIO import StringIO
1092.1.26 by Robert Collins
start writing star-topology test, realise we need smart-add change
18
import os
19
import unittest
20
1836.1.22 by John Arbash Meinel
[merge] bzr.dev 1861
21
from bzrlib import errors, ignores, osutils
1911.3.2 by John Arbash Meinel
Adding the AddFromBaseAction, which tries to reuse file ids from another tree
22
from bzrlib.add import (
23
    AddAction,
24
    AddFromBaseAction,
25
    smart_add,
26
    smart_add_tree,
27
    )
1830.3.6 by John Arbash Meinel
Test that smart_add_tree does the right thing in the presence of non-normalized filenames
28
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
1765.1.1 by Robert Collins
Remove the default ignores list from bzr, lowering the minimum overhead in bzr add.
29
from bzrlib.errors import NoSuchFile
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
30
from bzrlib.inventory import InventoryFile, Inventory
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
31
from bzrlib.workingtree import WorkingTree
1092.1.26 by Robert Collins
start writing star-topology test, realise we need smart-add change
32
1830.3.4 by John Arbash Meinel
A couple no-op cleanups
33
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
34
class TestSmartAdd(TestCaseWithTransport):
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
35
36
    def test_add_dot_from_root(self):
37
        """Test adding . from the root of the tree.""" 
38
        paths = ("original/", "original/file1", "original/file2")
39
        self.build_tree(paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
40
        wt = self.make_branch_and_tree('.')
41
        smart_add_tree(wt, (u".",))
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
42
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
43
            self.assertNotEqual(wt.path2id(path), None)
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
44
45
    def test_add_dot_from_subdir(self):
46
        """Test adding . from a subdir of the tree.""" 
47
        from bzrlib.add import smart_add
48
        paths = ("original/", "original/file1", "original/file2")
49
        self.build_tree(paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
50
        wt = self.make_branch_and_tree('.')
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
51
        os.chdir("original")
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
52
        smart_add_tree(wt, (u".",))
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
53
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
54
            self.assertNotEqual(wt.path2id(path), None)
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
55
56
    def test_add_tree_from_above_tree(self):
57
        """Test adding a tree from above the tree.""" 
58
        from bzrlib.add import smart_add
59
        paths = ("original/", "original/file1", "original/file2")
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
60
        branch_paths = ("branch/", "branch/original/", "branch/original/file1",
61
                        "branch/original/file2")
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
62
        self.build_tree(branch_paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
63
        wt = self.make_branch_and_tree('branch')
64
        smart_add_tree(wt, ("branch",))
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
65
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
66
            self.assertNotEqual(wt.path2id(path), None)
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
67
68
    def test_add_above_tree_preserves_tree(self):
69
        """Test nested trees are not affect by an add above them."""
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
70
        from bzrlib.add import smart_add
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
71
        paths = ("original/", "original/file1", "original/file2")
1143 by Martin Pool
- remove dead code and remove some small errors (pychecker)
72
        child_paths = ("path",)
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
73
        full_child_paths = ("original/child", "original/child/path")
74
        build_paths = ("original/", "original/file1", "original/file2", 
75
                       "original/child/", "original/child/path")
1143 by Martin Pool
- remove dead code and remove some small errors (pychecker)
76
        
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
77
        self.build_tree(build_paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
78
        wt = self.make_branch_and_tree('.')
79
        child_tree = self.make_branch_and_tree('original/child')
1757.2.9 by Robert Collins
Remove spurious u cast from test_smart_add.py
80
        smart_add_tree(wt, (".",))
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
81
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
82
            self.assertNotEqual((path, wt.path2id(path)),
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
83
                                (path, None))
84
        for path in full_child_paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
85
            self.assertEqual((path, wt.path2id(path)),
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
86
                             (path, None))
87
        for path in child_paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
88
            self.assertEqual(child_tree.path2id(path), None)
1092.1.28 by Robert Collins
test adding lists of paths
89
90
    def test_add_paths(self):
91
        """Test smart-adding a list of paths."""
92
        from bzrlib.add import smart_add
93
        paths = ("file1", "file2")
94
        self.build_tree(paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
95
        wt = self.make_branch_and_tree('.')
96
        smart_add_tree(wt, paths)
1092.1.28 by Robert Collins
test adding lists of paths
97
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
98
            self.assertNotEqual(wt.path2id(path), None)
1757.2.5 by Robert Collins
De-dup the add list so we only walk subtrees once for add.
99
    
100
    def test_add_ignored_nested_paths(self):
101
        """Test smart-adding a list of paths which includes ignored ones."""
102
        wt = self.make_branch_and_tree('.')
103
        tree_shape = ("adir/", "adir/CVS/", "adir/CVS/afile", "adir/CVS/afile2")
104
        add_paths = ("adir/CVS", "adir/CVS/afile", "adir")
105
        expected_paths = ("adir", "adir/CVS", "adir/CVS/afile", "adir/CVS/afile2")
106
        self.build_tree(tree_shape)
107
        smart_add_tree(wt, add_paths)
108
        for path in expected_paths:
109
            self.assertNotEqual(wt.path2id(path), None, "No id added for %s" % path)
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
110
111
    def test_add_dry_run(self):
112
        """Test a dry run add, make sure nothing is added."""
113
        from bzrlib.commands import run_bzr
114
        eq = self.assertEqual
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
115
        wt = self.make_branch_and_tree('.')
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
116
        self.build_tree(['inertiatic/', 'inertiatic/esp'])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
117
        eq(list(wt.unknowns()), ['inertiatic'])
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
118
        self.capture('add --dry-run .')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
119
        eq(list(wt.unknowns()), ['inertiatic'])
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
120
1185.56.2 by Michael Ellerman
Raise NoSuchFile when someone tries to add a non-existant file.
121
    def test_add_non_existant(self):
122
        """Test smart-adding a file that does not exist."""
123
        from bzrlib.add import smart_add
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
124
        wt = self.make_branch_and_tree('.')
125
        self.assertRaises(NoSuchFile, smart_add_tree, wt, 'non-existant-file')
1185.46.8 by Aaron Bentley
bzr add reports ignored patterns.
126
1765.1.1 by Robert Collins
Remove the default ignores list from bzr, lowering the minimum overhead in bzr add.
127
    def test_returns_and_ignores(self):
1185.46.8 by Aaron Bentley
bzr add reports ignored patterns.
128
        """Correctly returns added/ignored files"""
129
        from bzrlib.commands import run_bzr
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
130
        wt = self.make_branch_and_tree('.')
1836.1.15 by John Arbash Meinel
Updated WorkingTree to use the new user-level ignores.
131
        # The default ignore list includes '*.py[co]', but not CVS
1987.1.2 by John Arbash Meinel
Remove the unneeded _set_user_ignores(['./.bazaar']) now that home has moved
132
        ignores._set_user_ignores(['*.py[co]'])
1836.1.15 by John Arbash Meinel
Updated WorkingTree to use the new user-level ignores.
133
        self.build_tree(['inertiatic/', 'inertiatic/esp', 'inertiatic/CVS',
1185.46.8 by Aaron Bentley
bzr add reports ignored patterns.
134
                        'inertiatic/foo.pyc'])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
135
        added, ignored = smart_add_tree(wt, u'.')
1765.1.1 by Robert Collins
Remove the default ignores list from bzr, lowering the minimum overhead in bzr add.
136
        self.assertSubset(('inertiatic', 'inertiatic/esp', 'inertiatic/CVS'),
137
                          added)
1836.1.15 by John Arbash Meinel
Updated WorkingTree to use the new user-level ignores.
138
        self.assertSubset(('*.py[co]',), ignored)
139
        self.assertSubset(('inertiatic/foo.pyc',), ignored['*.py[co]'])
1185.46.8 by Aaron Bentley
bzr add reports ignored patterns.
140
141
1911.3.2 by John Arbash Meinel
Adding the AddFromBaseAction, which tries to reuse file ids from another tree
142
class AddCustomIDAction(AddAction):
1911.3.1 by John Arbash Meinel
Updated smart_add so that the AddAction can return a custom id.
143
144
    def __call__(self, inv, parent_ie, path, kind):
145
        # The first part just logs if appropriate
146
        # Now generate a custom id
2309.4.9 by John Arbash Meinel
WorkingTree.merged_modified() needs to switch back to utf8 file ids.
147
        file_id = osutils.safe_file_id(kind + '-'
148
                                       + path.raw_path.replace('/', '%'),
149
                                       warn=False)
1911.3.1 by John Arbash Meinel
Updated smart_add so that the AddAction can return a custom id.
150
        if self.should_print:
2309.4.9 by John Arbash Meinel
WorkingTree.merged_modified() needs to switch back to utf8 file ids.
151
            self._to_file.write('added %s with id %s\n'
1911.3.1 by John Arbash Meinel
Updated smart_add so that the AddAction can return a custom id.
152
                                % (path.raw_path, file_id))
153
        return file_id
154
155
1765.1.1 by Robert Collins
Remove the default ignores list from bzr, lowering the minimum overhead in bzr add.
156
class TestSmartAddTree(TestCaseWithTransport):
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
157
    """Test smart adds with a specified branch."""
158
159
    def test_add_dot_from_root(self):
160
        """Test adding . from the root of the tree.""" 
161
        paths = ("original/", "original/file1", "original/file2")
162
        self.build_tree(paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
163
        wt = self.make_branch_and_tree('.')
164
        smart_add_tree(wt, (u".",))
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
165
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
166
            self.assertNotEqual(wt.path2id(path), None)
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
167
168
    def test_add_dot_from_subdir(self):
169
        """Test adding . from a subdir of the tree.""" 
170
        paths = ("original/", "original/file1", "original/file2")
171
        self.build_tree(paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
172
        wt = self.make_branch_and_tree('.')
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
173
        os.chdir("original")
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
174
        smart_add_tree(wt, (u".",))
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
175
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
176
            self.assertNotEqual(wt.path2id(path), None)
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
177
178
    def test_add_tree_from_above_tree(self):
179
        """Test adding a tree from above the tree.""" 
180
        paths = ("original/", "original/file1", "original/file2")
181
        branch_paths = ("branch/", "branch/original/", "branch/original/file1",
182
                        "branch/original/file2")
183
        self.build_tree(branch_paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
184
        tree = self.make_branch_and_tree('branch')
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
185
        smart_add_tree(tree, ("branch",))
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
186
        for path in paths:
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
187
            self.assertNotEqual(tree.path2id(path), None)
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
188
189
    def test_add_above_tree_preserves_tree(self):
190
        """Test nested trees are not affect by an add above them."""
191
        paths = ("original/", "original/file1", "original/file2")
192
        child_paths = ("path")
193
        full_child_paths = ("original/child", "original/child/path")
194
        build_paths = ("original/", "original/file1", "original/file2", 
195
                       "original/child/", "original/child/path")
196
        self.build_tree(build_paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
197
        tree = self.make_branch_and_tree('.')
198
        child_tree = self.make_branch_and_tree("original/child")
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
199
        smart_add_tree(tree, (u".",))
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
200
        for path in paths:
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
201
            self.assertNotEqual((path, tree.path2id(path)),
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
202
                                (path, None))
203
        for path in full_child_paths:
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
204
            self.assertEqual((path, tree.path2id(path)),
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
205
                             (path, None))
206
        for path in child_paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
207
            self.assertEqual(child_tree.path2id(path), None)
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
208
209
    def test_add_paths(self):
210
        """Test smart-adding a list of paths."""
211
        paths = ("file1", "file2")
212
        self.build_tree(paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
213
        wt = self.make_branch_and_tree('.')
214
        smart_add_tree(wt, paths)
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
215
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
216
            self.assertNotEqual(wt.path2id(path), None)
217
1850.2.1 by John Arbash Meinel
Fix bug #52578, smart-add wasn't recursing all supplied directories.
218
    def test_add_multiple_dirs(self):
219
        """Test smart adding multiple directories at once."""
220
        added_paths = ['file1', 'file2',
221
                       'dir1/', 'dir1/file3',
222
                       'dir1/subdir2/', 'dir1/subdir2/file4',
223
                       'dir2/', 'dir2/file5',
224
                      ]
225
        not_added = ['file6', 'dir3/', 'dir3/file7', 'dir3/file8']
226
        self.build_tree(added_paths)
227
        self.build_tree(not_added)
228
229
        wt = self.make_branch_and_tree('.')
230
        smart_add_tree(wt, ['file1', 'file2', 'dir1', 'dir2'])
231
232
        for path in added_paths:
233
            self.assertNotEqual(None, wt.path2id(path.rstrip('/')),
234
                    'Failed to add path: %s' % (path,))
235
        for path in not_added:
236
            self.assertEqual(None, wt.path2id(path.rstrip('/')),
237
                    'Accidentally added path: %s' % (path,))
238
1911.3.1 by John Arbash Meinel
Updated smart_add so that the AddAction can return a custom id.
239
    def test_custom_ids(self):
240
        sio = StringIO()
1911.3.2 by John Arbash Meinel
Adding the AddFromBaseAction, which tries to reuse file ids from another tree
241
        action = AddCustomIDAction(to_file=sio, should_print=True)
1911.3.1 by John Arbash Meinel
Updated smart_add so that the AddAction can return a custom id.
242
        self.build_tree(['file1', 'dir1/', 'dir1/file2'])
243
244
        wt = self.make_branch_and_tree('.')
245
        smart_add_tree(wt, ['.'], action=action)
1911.3.5 by John Arbash Meinel
There is no strict ordering file addition, other than directories are added before child files
246
        # The order of adds is not strictly fixed:
247
        sio.seek(0)
248
        lines = sorted(sio.readlines())
249
        self.assertEqualDiff(['added dir1 with id directory-dir1\n',
250
                              'added dir1/file2 with id file-dir1%file2\n',
251
                              'added file1 with id file-file1\n',
252
                             ], lines)
2255.7.57 by Robert Collins
Fix test_smart_add tests for dirstate - mainly inventory outside locks issues.
253
        wt.lock_read()
254
        self.addCleanup(wt.unlock)
255
        self.assertEqual([('', wt.path2id('')),
1911.3.1 by John Arbash Meinel
Updated smart_add so that the AddAction can return a custom id.
256
                          ('dir1', 'directory-dir1'),
257
                          ('dir1/file2', 'file-dir1%file2'),
258
                          ('file1', 'file-file1'),
259
                         ], [(path, ie.file_id) for path, ie
260
                                in wt.inventory.iter_entries()])
261
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
262
1911.3.2 by John Arbash Meinel
Adding the AddFromBaseAction, which tries to reuse file ids from another tree
263
class TestAddFrom(TestCaseWithTransport):
264
    """Tests for AddFromBaseAction"""
265
266
    def make_base_tree(self):
267
        self.base_tree = self.make_branch_and_tree('base')
268
        self.build_tree(['base/a', 'base/b',
269
                         'base/dir/', 'base/dir/a',
270
                         'base/dir/subdir/',
271
                         'base/dir/subdir/b',
272
                        ])
273
        self.base_tree.add(['a', 'b', 'dir', 'dir/a',
274
                            'dir/subdir', 'dir/subdir/b'])
275
        self.base_tree.commit('creating initial tree.')
276
277
    def add_helper(self, base_tree, base_path, new_tree, file_list,
278
                   should_print=False):
279
        to_file = StringIO()
280
        base_tree.lock_read()
281
        try:
282
            new_tree.lock_write()
283
            try:
284
                action = AddFromBaseAction(base_tree, base_path,
285
                                           to_file=to_file,
286
                                           should_print=should_print)
287
                smart_add_tree(new_tree, file_list, action=action)
288
            finally:
289
                new_tree.unlock()
290
        finally:
291
            base_tree.unlock()
292
        return to_file.getvalue()
293
294
    def test_copy_all(self):
295
        self.make_base_tree()
296
        new_tree = self.make_branch_and_tree('new')
297
        files = ['a', 'b',
298
                 'dir/', 'dir/a',
299
                 'dir/subdir/',
300
                 'dir/subdir/b',
301
                ]
302
        self.build_tree(['new/' + fn for fn in files])
303
        self.add_helper(self.base_tree, '', new_tree, ['new'])
304
305
        for fn in files:
306
            base_file_id = self.base_tree.path2id(fn)
307
            new_file_id = new_tree.path2id(fn)
308
            self.assertEqual(base_file_id, new_file_id)
309
310
    def test_copy_from_dir(self):
311
        self.make_base_tree()
312
        new_tree = self.make_branch_and_tree('new')
313
314
        self.build_tree(['new/a', 'new/b', 'new/c',
315
                         'new/subdir/', 'new/subdir/b', 'new/subdir/d'])
1731.1.46 by Aaron Bentley
merge from bzr.dev
316
        new_tree.set_root_id(self.base_tree.get_root_id())
1911.3.2 by John Arbash Meinel
Adding the AddFromBaseAction, which tries to reuse file ids from another tree
317
        self.add_helper(self.base_tree, 'dir', new_tree, ['new'])
318
1731.1.46 by Aaron Bentley
merge from bzr.dev
319
        # We know 'a' and 'b' exist in the root, and they are being added
320
        # in a new 'root'. Since ROOT ids have been set as the same, we will
1911.3.2 by John Arbash Meinel
Adding the AddFromBaseAction, which tries to reuse file ids from another tree
321
        # use those ids
322
        self.assertEqual(self.base_tree.path2id('a'),
323
                         new_tree.path2id('a'))
324
        self.assertEqual(self.base_tree.path2id('b'),
325
                         new_tree.path2id('b'))
326
327
        # Because we specified 'dir/' as the base path, and we have
328
        # nothing named 'subdir' in the base tree, we should grab the
329
        # ids from there
330
        self.assertEqual(self.base_tree.path2id('dir/subdir'),
331
                         new_tree.path2id('subdir'))
332
        self.assertEqual(self.base_tree.path2id('dir/subdir/b'),
333
                         new_tree.path2id('subdir/b'))
334
335
        # These should get newly generated ids
336
        c_id = new_tree.path2id('c')
337
        self.assertNotEqual(None, c_id)
2255.7.57 by Robert Collins
Fix test_smart_add tests for dirstate - mainly inventory outside locks issues.
338
        self.base_tree.lock_read()
339
        self.addCleanup(self.base_tree.unlock)
1911.3.2 by John Arbash Meinel
Adding the AddFromBaseAction, which tries to reuse file ids from another tree
340
        self.failIf(c_id in self.base_tree)
341
342
        d_id = new_tree.path2id('subdir/d')
343
        self.assertNotEqual(None, d_id)
344
        self.failIf(d_id in self.base_tree)
345
346
    def test_copy_existing_dir(self):
347
        self.make_base_tree()
348
        new_tree = self.make_branch_and_tree('new')
349
        self.build_tree(['new/subby/', 'new/subby/a', 'new/subby/b'])
350
351
        subdir_file_id = self.base_tree.path2id('dir/subdir')
352
        new_tree.add(['subby'], [subdir_file_id])
353
        self.add_helper(self.base_tree, '', new_tree, ['new'])
354
        # Because 'subby' already points to subdir, we should add
355
        # 'b' with the same id
356
        self.assertEqual(self.base_tree.path2id('dir/subdir/b'),
357
                         new_tree.path2id('subby/b'))
358
359
        # 'subby/a' should be added with a new id because there is no
360
        # matching path or child of 'subby'.
361
        a_id = new_tree.path2id('subby/a')
362
        self.assertNotEqual(None, a_id)
2255.7.57 by Robert Collins
Fix test_smart_add tests for dirstate - mainly inventory outside locks issues.
363
        self.base_tree.lock_read()
364
        self.addCleanup(self.base_tree.unlock)
1911.3.2 by John Arbash Meinel
Adding the AddFromBaseAction, which tries to reuse file ids from another tree
365
        self.failIf(a_id in self.base_tree)
366
367
1830.3.6 by John Arbash Meinel
Test that smart_add_tree does the right thing in the presence of non-normalized filenames
368
class TestAddNonNormalized(TestCaseWithTransport):
369
370
    def make(self):
371
        try:
372
            self.build_tree([u'a\u030a'])
373
        except UnicodeError:
374
            raise TestSkipped('Filesystem cannot create unicode filenames')
375
376
        self.wt = self.make_branch_and_tree('.')
377
378
    def test_accessible_explicit(self):
379
        self.make()
380
        orig = osutils.normalized_filename
381
        osutils.normalized_filename = osutils._accessible_normalized_filename
382
        try:
383
            smart_add_tree(self.wt, [u'a\u030a'])
2255.7.57 by Robert Collins
Fix test_smart_add tests for dirstate - mainly inventory outside locks issues.
384
            self.wt.lock_read()
385
            self.addCleanup(self.wt.unlock)
1907.1.3 by Aaron Bentley
Fixed unicode test cases
386
            self.assertEqual([('', 'directory'), (u'\xe5', 'file')],
1830.3.17 by John Arbash Meinel
list_files() with wrong normalized_filename code raises exceptions. Fix this
387
                    [(path, ie.kind) for path,ie in 
388
                        self.wt.inventory.iter_entries()])
1830.3.6 by John Arbash Meinel
Test that smart_add_tree does the right thing in the presence of non-normalized filenames
389
        finally:
390
            osutils.normalized_filename = orig
391
392
    def test_accessible_implicit(self):
393
        self.make()
394
        orig = osutils.normalized_filename
395
        osutils.normalized_filename = osutils._accessible_normalized_filename
396
        try:
397
            smart_add_tree(self.wt, [])
2255.7.57 by Robert Collins
Fix test_smart_add tests for dirstate - mainly inventory outside locks issues.
398
            self.wt.lock_read()
399
            self.addCleanup(self.wt.unlock)
1907.1.3 by Aaron Bentley
Fixed unicode test cases
400
            self.assertEqual([('', 'directory'), (u'\xe5', 'file')],
1830.3.17 by John Arbash Meinel
list_files() with wrong normalized_filename code raises exceptions. Fix this
401
                    [(path, ie.kind) for path,ie in 
402
                        self.wt.inventory.iter_entries()])
1830.3.6 by John Arbash Meinel
Test that smart_add_tree does the right thing in the presence of non-normalized filenames
403
        finally:
404
            osutils.normalized_filename = orig
405
406
    def test_inaccessible_explicit(self):
407
        self.make()
408
        orig = osutils.normalized_filename
409
        osutils.normalized_filename = osutils._inaccessible_normalized_filename
410
        try:
411
            self.assertRaises(errors.InvalidNormalization,
412
                    smart_add_tree, self.wt, [u'a\u030a'])
413
        finally:
414
            osutils.normalized_filename = orig
415
416
    def test_inaccessible_implicit(self):
417
        self.make()
418
        orig = osutils.normalized_filename
419
        osutils.normalized_filename = osutils._inaccessible_normalized_filename
420
        try:
421
            # TODO: jam 20060701 In the future, this should probably
422
            #       just ignore files that don't fit the normalization
423
            #       rules, rather than exploding
424
            self.assertRaises(errors.InvalidNormalization,
425
                    smart_add_tree, self.wt, [])
426
        finally:
427
            osutils.normalized_filename = orig
428
429
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
430
class TestAddActions(TestCase):
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
431
1757.2.6 by Robert Collins
Steps towards a nicer smart add - unwind the conditional add logic - having parents not in the inventory was overly complicating the rest of the code.
432
    def test_quiet(self):
433
        self.run_action("")
434
435
    def test__print(self):
436
        self.run_action("added path\n")
437
438
    def run_action(self, output):
1757.2.3 by Robert Collins
Get add tests passing.
439
        from bzrlib.add import AddAction, FastPath
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
440
        inv = Inventory()
1092.1.30 by Robert Collins
change smart_add reporting of added files to callback with the entry, and change the inventory.add signature to return the added entry
441
        stdout = StringIO()
1757.2.6 by Robert Collins
Steps towards a nicer smart add - unwind the conditional add logic - having parents not in the inventory was overly complicating the rest of the code.
442
        action = AddAction(to_file=stdout, should_print=bool(output))
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
443
1757.2.3 by Robert Collins
Get add tests passing.
444
        self.apply_redirected(None, stdout, None, action, inv, None, FastPath('path'), 'file')
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
445
        self.assertEqual(stdout.getvalue(), output)