1# Software License Agreement (BSD License) 2# 3# Copyright (c) 2009, Willow Garage, Inc. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 10# * Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# * Redistributions in binary form must reproduce the above 13# copyright notice, this list of conditions and the following 14# disclaimer in the documentation and/or other materials provided 15# with the distribution. 16# * Neither the name of Willow Garage, Inc. nor the names of its 17# contributors may be used to endorse or promote products derived 18# from this software without specific prior written permission. 19# 20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31# POSSIBILITY OF SUCH DAMAGE. 32 33import os 34import sys 35import subprocess 36 37from test.io_wrapper import StringIO 38 39import wstool 40import wstool.helpers 41import wstool.wstool_cli 42from wstool.wstool_cli import WstoolCLI 43from wstool.wstool_cli import wstool_main 44 45import test.scm_test_base 46from test.scm_test_base import AbstractSCMTest, _add_to_file, _nth_line_split 47 48 49def create_git_repo(remote_path): 50 # create a "remote" repo 51 subprocess.check_call(["git", "init"], cwd=remote_path) 52 subprocess.check_call(["touch", "fixed.txt"], cwd=remote_path) 53 subprocess.check_call(["touch", "modified.txt"], cwd=remote_path) 54 subprocess.check_call(["touch", "modified-fs.txt"], cwd=remote_path) 55 subprocess.check_call(["touch", "deleted.txt"], cwd=remote_path) 56 subprocess.check_call(["touch", "deleted-fs.txt"], cwd=remote_path) 57 subprocess.check_call(["git", "add", "*"], cwd=remote_path) 58 subprocess.check_call(["git", "commit", "-m", "modified"], cwd=remote_path) 59 60 61def modify_git_repo(clone_path): 62 # make local modifications 63 subprocess.check_call(["rm", "deleted-fs.txt"], cwd=clone_path) 64 subprocess.check_call(["git", "rm", "deleted.txt"], cwd=clone_path) 65 _add_to_file(os.path.join(clone_path, "modified-fs.txt"), "foo\n") 66 _add_to_file(os.path.join(clone_path, "modified.txt"), "foo\n") 67 subprocess.check_call(["git", "add", "modified.txt"], cwd=clone_path) 68 _add_to_file(os.path.join(clone_path, "added-fs.txt"), "tada\n") 69 _add_to_file(os.path.join(clone_path, "added.txt"), "flam\n") 70 subprocess.check_call(["git", "add", "added.txt"], cwd=clone_path) 71 72 73class WstoolDiffGitTest(AbstractSCMTest): 74 75 @classmethod 76 def setUpClass(self): 77 AbstractSCMTest.setUpClass() 78 remote_path = os.path.join(self.test_root_path, "remote") 79 os.makedirs(remote_path) 80 81 create_git_repo(remote_path) 82 83 # wstool the remote repo and fake ros 84 _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- git: {local-name: clone, uri: ../remote}") 85 86 cmd = ["wstool", "update", "-t", "ws"] 87 os.chdir(self.test_root_path) 88 wstool_main(cmd) 89 90 clone_path = os.path.join(self.local_path, "clone") 91 92 modify_git_repo(clone_path) 93 94 def check_diff_output(self, output): 95 # sha ids are always same with git 96 self.assertEqual('diff --git clone/added.txt clone/added.txt\nnew file mode 100644\nindex 0000000..8d63207\n--- /dev/null\n+++ clone/added.txt\n@@ -0,0 +1 @@\n+flam\ndiff --git clone/deleted-fs.txt clone/deleted-fs.txt\ndeleted file mode 100644\nindex e69de29..0000000\ndiff --git clone/deleted.txt clone/deleted.txt\ndeleted file mode 100644\nindex e69de29..0000000\ndiff --git clone/modified-fs.txt clone/modified-fs.txt\nindex e69de29..257cc56 100644\n--- clone/modified-fs.txt\n+++ clone/modified-fs.txt\n@@ -0,0 +1 @@\n+foo\ndiff --git clone/modified.txt clone/modified.txt\nindex e69de29..257cc56 100644\n--- clone/modified.txt\n+++ clone/modified.txt\n@@ -0,0 +1 @@\n+foo', output.rstrip()) 97 98 def test_wstool_diff_git_outside(self): 99 """Test diff output for git when run outside workspace""" 100 101 cmd = ["wstool", "diff", "-t", "ws"] 102 os.chdir(self.test_root_path) 103 sys.stdout = output = StringIO() 104 wstool_main(cmd) 105 sys.stdout = sys.__stdout__ 106 output = output.getvalue() 107 self.check_diff_output(output) 108 109 cli = WstoolCLI() 110 self.assertEqual(0, cli.cmd_diff(os.path.join(self.test_root_path, 'ws'), [])) 111 112 def test_wstool_diff_git_inside(self): 113 """Test diff output for git when run inside workspace""" 114 directory = self.test_root_path + "/ws" 115 cmd = ["wstool", "diff"] 116 os.chdir(directory) 117 sys.stdout = output = StringIO() 118 wstool_main(cmd) 119 output = output.getvalue() 120 sys.stdout = sys.__stdout__ 121 self.check_diff_output(output) 122 123 cli = WstoolCLI() 124 self.assertEqual(0, cli.cmd_diff(directory, [])) 125 126 def test_wstool_status_git_inside(self): 127 """Test status output for git when run inside workspace""" 128 directory = self.test_root_path + "/ws" 129 130 cmd = ["wstool", "status"] 131 os.chdir(directory) 132 sys.stdout = output = StringIO() 133 wstool_main(cmd) 134 output = output.getvalue() 135 sys.stdout = sys.__stdout__ 136 self.assertEqual('A clone/added.txt\n D clone/deleted-fs.txt\nD clone/deleted.txt\n M clone/modified-fs.txt\nM clone/modified.txt\n', output) 137 138 cli = WstoolCLI() 139 self.assertEqual(0, cli.cmd_diff(directory, [])) 140 141 def test_Wstool_status_git_outside(self): 142 """Test status output for git when run outside workspace""" 143 144 cmd = ["wstool", "status", "-t", "ws"] 145 os.chdir(self.test_root_path) 146 sys.stdout = output = StringIO() 147 wstool_main(cmd) 148 sys.stdout = sys.__stdout__ 149 output = output.getvalue() 150 self.assertEqual('A clone/added.txt\n D clone/deleted-fs.txt\nD clone/deleted.txt\n M clone/modified-fs.txt\nM clone/modified.txt\n', output) 151 152 cli = WstoolCLI() 153 self.assertEqual(0, cli.cmd_status(os.path.join(self.test_root_path, 'ws'), [])) 154 155 def test_Wstool_status_git_untracked(self): 156 """Test untracked status output for git when run outside workspace""" 157 158 cmd = ["wstool", "status", "-t", "ws", "--untracked"] 159 os.chdir(self.test_root_path) 160 sys.stdout = output = StringIO() 161 wstool_main(cmd) 162 sys.stdout = sys.__stdout__ 163 output = output.getvalue() 164 self.assertEqual('A clone/added.txt\n D clone/deleted-fs.txt\nD clone/deleted.txt\n M clone/modified-fs.txt\nM clone/modified.txt\n?? clone/added-fs.txt\n', output) 165 166 cli = WstoolCLI() 167 self.assertEqual(0, cli.cmd_status(os.path.join(self.test_root_path, 'ws'), ["--untracked"])) 168 169 def test_wstool_info_git(self): 170 cmd = ["wstool", "info", "-t", "ws"] 171 os.chdir(self.test_root_path) 172 sys.stdout = output = StringIO() 173 wstool_main(cmd) 174 output = output.getvalue() 175 tokens = _nth_line_split(-2, output) 176 self.assertEqual(['clone', 'M', 'git'], tokens[0:3]) 177 tokens2 = _nth_line_split(-1, output) 178 self.assertEqual(1, len(tokens2)) 179 self.assertEqual('../ros', tokens2[0]) 180 181 cli = WstoolCLI() 182 self.assertEqual(0, cli.cmd_info(os.path.join(self.test_root_path, 'ws'), [])) 183 184 185class WstoolInfoGitTest(AbstractSCMTest): 186 187 def setUp(self): 188 AbstractSCMTest.setUp(self) 189 self.remote_path = os.path.join(self.test_root_path, "remote") 190 os.makedirs(self.remote_path) 191 192 # create a "remote" repo 193 subprocess.check_call(["git", "init"], cwd=self.remote_path) 194 subprocess.check_call(["touch", "test.txt"], cwd=self.remote_path) 195 subprocess.check_call(["git", "add", "*"], cwd=self.remote_path) 196 subprocess.check_call(["git", "commit", "-m", "modified"], cwd=self.remote_path) 197 po = subprocess.Popen(["git", "log", "-n", "1", "--pretty=format:\"%H\""], cwd=self.remote_path, stdout=subprocess.PIPE) 198 self.version_init = po.stdout.read().decode('UTF-8').rstrip('"').lstrip('"')[0:12] 199 subprocess.check_call(["git", "tag", "footag"], cwd=self.remote_path) 200 subprocess.check_call(["touch", "test2.txt"], cwd=self.remote_path) 201 subprocess.check_call(["git", "add", "*"], cwd=self.remote_path) 202 subprocess.check_call(["git", "commit", "-m", "modified"], cwd=self.remote_path) 203 po = subprocess.Popen(["git", "log", "-n", "1", "--pretty=format:\"%H\""], cwd=self.remote_path, stdout=subprocess.PIPE) 204 self.version_end = po.stdout.read().decode('UTF-8').rstrip('"').lstrip('"')[0:12] 205 206 # wstool the remote repo and fake ros 207 _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- git: {local-name: clone, uri: ../remote}") 208 self.clone_path = os.path.join(self.local_path, "clone") 209 210 cmd = ["wstool", "update"] 211 os.chdir(self.local_path) 212 sys.stdout = output = StringIO() 213 wstool_main(cmd) 214 output = output.getvalue() 215 sys.stdout = sys.__stdout__ 216 217 def test_wstool_detailed_localpath_info(self): 218 cmd = ["wstool", "info", "-t", "ws", "--managed-only"] 219 os.chdir(self.test_root_path) 220 sys.stdout = output = StringIO() 221 wstool_main(cmd) 222 output = output.getvalue() 223 tokens = _nth_line_split(-2, output) 224 self.assertEqual(['clone', 'git', 'master', '(-)', self.version_end, self.remote_path], tokens) 225 226 # test when remote version is different 227 subprocess.check_call(["git", "reset", "--hard", "HEAD~1"], cwd=self.clone_path) 228 sys.stdout = output = StringIO() 229 wstool_main(cmd) 230 output = output.getvalue() 231 tokens = _nth_line_split(-2, output) 232 self.assertEqual(['clone', 'C', 'git', 'master', '(-)', self.version_init, self.remote_path], tokens) 233 # return branch back to original revision 234 subprocess.check_call(["git", "reset", "--hard", self.version_end], cwd=self.clone_path) 235 236 # make local modifications check 237 subprocess.check_call(["rm", "test2.txt"], cwd=self.clone_path) 238 sys.stdout = output = StringIO() 239 wstool_main(cmd) 240 output = output.getvalue() 241 tokens = _nth_line_split(-2, output) 242 self.assertEqual(['clone', 'M', 'git', 'master', '(-)', self.version_end, self.remote_path], tokens) 243 244 subprocess.check_call(["rm", ".rosinstall"], cwd=self.local_path) 245 _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- git: {local-name: clone, uri: ../remote, version: \"footag\"}") 246 # test when version is different 247 sys.stdout = output = StringIO() 248 wstool_main(cmd) 249 output = output.getvalue() 250 tokens = _nth_line_split(-2, output) 251 self.assertEqual(['clone', 'MV', 'git', 'master', '(footag)', self.version_end, "(%s)" % self.version_init, self.remote_path], tokens) 252 # test when tracking branch is different from current branch 253 subprocess.check_call(["git", "checkout", "-b", "test_branch"], cwd=self.clone_path) 254 subprocess.check_call(["git", "config", "--replace-all", "branch.test_branch.remote", "origin"], cwd=self.clone_path) 255 subprocess.check_call(["git", "config", "--replace-all", "branch.test_branch.merge", "master"], cwd=self.clone_path) 256 sys.stdout = output = StringIO() 257 wstool_main(cmd) 258 output = output.getvalue() 259 tokens = _nth_line_split(-2, output) 260 self.assertEqual(['clone', 'MV', 'git', 'test_branch', '<', 'master', '(footag)', self.version_end, "(%s)" % self.version_init, self.remote_path], tokens) 261 262 # test when remote is different from origin by rename 263 subprocess.check_call(["git", "remote", "rename", "origin", "remote2"], cwd=self.clone_path) 264 subprocess.check_call(["git", "config", "--replace-all", "branch.test_branch.remote", "remote2"], cwd=self.clone_path) 265 sys.stdout = output = StringIO() 266 wstool_main(cmd) 267 output = output.getvalue() 268 tokens = _nth_line_split(-2, output) 269 self.assertEqual(['clone', 'MV', 'git', 'test_branch', '<', 'remote2/master', '(footag)', self.version_end, "(%s)" % self.version_init, "(%s)" % self.remote_path], tokens) 270 # return remote name to origin 271 subprocess.check_call(["git", "remote", "rename", "remote2", "origin"], cwd=self.clone_path) 272 273 # test when remote is different from origin, no fetch 274 subprocess.check_call(["git", "remote", "add", "remote2", "../../remote"], cwd=self.clone_path) 275 subprocess.check_call(["git", "config", "--replace-all", "branch.test_branch.remote", "remote2"], cwd=self.clone_path) 276 sys.stdout = output = StringIO() 277 wstool_main(cmd) 278 output = output.getvalue() 279 tokens = _nth_line_split(-2, output) 280 self.assertEqual(['clone', 'MV', 'git', 'test_branch', '(footag)', self.version_end, "(%s)" % self.version_init, self.remote_path], tokens) 281 282 283 # test when remote is different from origin, with fetch 284 sys.stdout = output = StringIO() 285 wstool_main(cmd + ['--fetch']) 286 output = output.getvalue() 287 tokens = _nth_line_split(-2, output) 288 self.assertEqual(['clone', 'MV', 'git', 'test_branch', '<', 'remote2/master', '(footag)', self.version_end, "(%s)" % self.version_init, self.remote_path], tokens) 289 290 291 # return branch back to master 292 subprocess.check_call(["git", "checkout", "master"], cwd=self.clone_path) 293 294 # using a denormalized local-name here 295 subprocess.check_call(["rm", ".rosinstall"], cwd=self.local_path) 296 _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- git: {local-name: clone/../clone, uri: ../remote, version: \"footag\"}") 297 sys.stdout = output = StringIO() 298 wstool_main(cmd) 299 output = output.getvalue() 300 tokens = _nth_line_split(-2, output) 301 self.assertEqual(['clone', 'MV', 'git', 'master', '(footag)', self.version_end, "(%s)" % 302 self.version_init, self.remote_path], tokens) 303 304 # using an absolute path to clone dir here 305 subprocess.check_call(["rm", ".rosinstall"], cwd=self.local_path) 306 _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- git: {local-name: '"+self.clone_path+"', uri: ../remote, version: \"footag\"}") 307 sys.stdout = output = StringIO() 308 wstool_main(cmd) 309 output = output.getvalue() 310 tokens = _nth_line_split(-2, output) 311 self.assertEqual([self.clone_path, 'MV', 'git', 'master', '(footag)', self.version_end, "(%s)" % self.version_init, self.remote_path], tokens) 312 313 # using an absolute path here where relative path is shorter to display (also checks x for missing) 314 subprocess.check_call(["rm", ".rosinstall"], cwd=self.local_path) 315 _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- git: {local-name: '"+os.path.join(self.local_path, "../foo")+"', uri: ../remote, version: \"footag\"}") 316 sys.stdout = output = StringIO() 317 wstool_main(cmd) 318 output = output.getvalue() 319 tokens = _nth_line_split(-2, output) 320 localname = os.path.join(os.path.dirname(self.local_path), 'foo') 321 self.assertEqual([localname, 'x', 'git', '(footag)', self.remote_path], tokens) 322