1# Copyright (C) 2005, 2006, 2007, 2009, 2010 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 17from io import StringIO 18 19from .. import ( 20 add, 21 cache_utf8, 22 errors, 23 tests, 24 ) 25from ..bzr import ( 26 inventory, 27 ) 28 29 30class AddCustomIDAction(add.AddAction): 31 32 def __call__(self, inv, parent_ie, path, kind): 33 # The first part just logs if appropriate 34 # Now generate a custom id 35 file_id = cache_utf8.encode(kind + '-' + path.replace('/', '%')) 36 if self.should_print: 37 self._to_file.write('added %s with id %s\n' 38 % (path, file_id.decode('utf-8'))) 39 return file_id 40 41 42class TestAddFrom(tests.TestCaseWithTransport): 43 """Tests for AddFromBaseAction""" 44 45 def make_base_tree(self): 46 self.base_tree = self.make_branch_and_tree('base') 47 self.build_tree(['base/a', 'base/b', 48 'base/dir/', 'base/dir/a', 49 'base/dir/subdir/', 50 'base/dir/subdir/b', 51 ]) 52 self.base_tree.add(['a', 'b', 'dir', 'dir/a', 53 'dir/subdir', 'dir/subdir/b']) 54 self.base_tree.commit('creating initial tree.') 55 56 def add_helper(self, base_tree, base_path, new_tree, file_list, 57 should_print=False): 58 to_file = StringIO() 59 base_tree.lock_read() 60 try: 61 new_tree.lock_write() 62 try: 63 action = add.AddFromBaseAction(base_tree, base_path, 64 to_file=to_file, 65 should_print=should_print) 66 new_tree.smart_add(file_list, action=action) 67 finally: 68 new_tree.unlock() 69 finally: 70 base_tree.unlock() 71 return to_file.getvalue() 72 73 def test_copy_all(self): 74 self.make_base_tree() 75 new_tree = self.make_branch_and_tree('new') 76 files = ['a', 'b', 77 'dir/', 'dir/a', 78 'dir/subdir/', 79 'dir/subdir/b', 80 ] 81 self.build_tree(['new/' + fn for fn in files]) 82 self.add_helper(self.base_tree, '', new_tree, ['new']) 83 84 for fn in files: 85 base_file_id = self.base_tree.path2id(fn) 86 new_file_id = new_tree.path2id(fn) 87 self.assertEqual(base_file_id, new_file_id) 88 89 def test_copy_from_dir(self): 90 self.make_base_tree() 91 new_tree = self.make_branch_and_tree('new') 92 93 self.build_tree(['new/a', 'new/b', 'new/c', 94 'new/subdir/', 'new/subdir/b', 'new/subdir/d']) 95 new_tree.set_root_id(self.base_tree.path2id('')) 96 self.add_helper(self.base_tree, 'dir', new_tree, ['new']) 97 98 # We know 'a' and 'b' exist in the root, and they are being added 99 # in a new 'root'. Since ROOT ids have been set as the same, we will 100 # use those ids 101 self.assertEqual(self.base_tree.path2id('a'), 102 new_tree.path2id('a')) 103 self.assertEqual(self.base_tree.path2id('b'), 104 new_tree.path2id('b')) 105 106 # Because we specified 'dir/' as the base path, and we have 107 # nothing named 'subdir' in the base tree, we should grab the 108 # ids from there 109 self.assertEqual(self.base_tree.path2id('dir/subdir'), 110 new_tree.path2id('subdir')) 111 self.assertEqual(self.base_tree.path2id('dir/subdir/b'), 112 new_tree.path2id('subdir/b')) 113 114 # These should get newly generated ids 115 c_id = new_tree.path2id('c') 116 self.assertNotEqual(None, c_id) 117 self.base_tree.lock_read() 118 self.addCleanup(self.base_tree.unlock) 119 self.assertRaises(errors.NoSuchId, self.base_tree.id2path, c_id) 120 121 d_id = new_tree.path2id('subdir/d') 122 self.assertNotEqual(None, d_id) 123 self.assertRaises(errors.NoSuchId, self.base_tree.id2path, d_id) 124 125 def test_copy_existing_dir(self): 126 self.make_base_tree() 127 new_tree = self.make_branch_and_tree('new') 128 self.build_tree(['new/subby/', 'new/subby/a', 'new/subby/b']) 129 130 subdir_file_id = self.base_tree.path2id('dir/subdir') 131 new_tree.add(['subby'], [subdir_file_id]) 132 self.add_helper(self.base_tree, '', new_tree, ['new']) 133 # Because 'subby' already points to subdir, we should add 134 # 'b' with the same id 135 self.assertEqual(self.base_tree.path2id('dir/subdir/b'), 136 new_tree.path2id('subby/b')) 137 138 # 'subby/a' should be added with a new id because there is no 139 # matching path or child of 'subby'. 140 a_id = new_tree.path2id('subby/a') 141 self.assertNotEqual(None, a_id) 142 self.base_tree.lock_read() 143 self.addCleanup(self.base_tree.unlock) 144 self.assertRaises(errors.NoSuchId, self.base_tree.id2path, a_id) 145 146 147class TestAddActions(tests.TestCase): 148 149 def test_quiet(self): 150 self.run_action("") 151 152 def test__print(self): 153 self.run_action("adding path\n") 154 155 def run_action(self, output): 156 inv = inventory.Inventory() 157 stdout = StringIO() 158 action = add.AddAction(to_file=stdout, should_print=bool(output)) 159 160 self.apply_redirected(None, stdout, None, action, inv, None, 161 'path', 'file') 162 self.assertEqual(stdout.getvalue(), output) 163