1#!/usr/bin/env python 2# 3# update_tests.py: testing update cases. 4# 5# Subversion is a tool for revision control. 6# See http://subversion.apache.org for more information. 7# 8# ==================================================================== 9# Licensed to the Apache Software Foundation (ASF) under one 10# or more contributor license agreements. See the NOTICE file 11# distributed with this work for additional information 12# regarding copyright ownership. The ASF licenses this file 13# to you under the Apache License, Version 2.0 (the 14# "License"); you may not use this file except in compliance 15# with the License. You may obtain a copy of the License at 16# 17# http://www.apache.org/licenses/LICENSE-2.0 18# 19# Unless required by applicable law or agreed to in writing, 20# software distributed under the License is distributed on an 21# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 22# KIND, either express or implied. See the License for the 23# specific language governing permissions and limitations 24# under the License. 25###################################################################### 26 27# General modules 28import sys, re, os, subprocess 29import time 30import logging 31 32logger = logging.getLogger() 33 34# Our testing module 35import svntest 36from svntest import wc, actions, verify, deeptrees 37from svntest.mergetrees import expected_merge_output 38from svntest.mergetrees import set_up_branch 39 40# (abbreviation) 41Skip = svntest.testcase.Skip_deco 42SkipUnless = svntest.testcase.SkipUnless_deco 43XFail = svntest.testcase.XFail_deco 44Issues = svntest.testcase.Issues_deco 45Issue = svntest.testcase.Issue_deco 46Wimp = svntest.testcase.Wimp_deco 47Item = svntest.wc.StateItem 48exp_noop_up_out = svntest.actions.expected_noop_update_output 49 50from svntest.main import SVN_PROP_MERGEINFO, server_has_mergeinfo 51 52###################################################################### 53# Tests 54# 55# Each test must return on success or raise on failure. 56 57 58 59def update_binary_file(sbox): 60 "update a locally-modified binary file" 61 62 sbox.build() 63 wc_dir = sbox.wc_dir 64 65 # Add a binary file to the project. 66 theta_contents = open(os.path.join(sys.path[0], "theta.bin"), 'rb').read() 67 # Write PNG file data into 'A/theta'. 68 theta_path = sbox.ospath('A/theta') 69 svntest.main.file_write(theta_path, theta_contents, 'wb') 70 71 svntest.main.run_svn(None, 'add', theta_path) 72 73 # Created expected output tree for 'svn ci' 74 expected_output = svntest.wc.State(wc_dir, { 75 'A/theta' : Item(verb='Adding (bin)'), 76 }) 77 78 # Create expected status tree 79 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 80 expected_status.add({ 81 'A/theta' : Item(status=' ', wc_rev=2), 82 }) 83 84 # Commit the new binary file, creating revision 2. 85 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 86 expected_status) 87 88 # Make a backup copy of the working copy. 89 wc_backup = sbox.add_wc_path('backup') 90 svntest.actions.duplicate_dir(wc_dir, wc_backup) 91 theta_backup_path = os.path.join(wc_backup, 'A', 'theta') 92 93 # Make a change to the binary file in the original working copy 94 svntest.main.file_append(theta_path, "revision 3 text") 95 theta_contents_r3 = theta_contents + b"revision 3 text" 96 97 # Created expected output tree for 'svn ci' 98 expected_output = svntest.wc.State(wc_dir, { 99 'A/theta' : Item(verb='Sending'), 100 }) 101 102 # Create expected status tree 103 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 104 expected_status.add({ 105 'A/theta' : Item(status=' ', wc_rev=3), 106 }) 107 108 # Commit original working copy again, creating revision 3. 109 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 110 expected_status) 111 112 # Now start working in the backup working copy: 113 114 # Make a local mod to theta 115 svntest.main.file_append(theta_backup_path, "extra theta text") 116 theta_contents_local = theta_contents + b"extra theta text" 117 118 # Create expected output tree for an update of wc_backup. 119 expected_output = svntest.wc.State(wc_backup, { 120 'A/theta' : Item(status='C '), 121 }) 122 123 # Create expected disk tree for the update -- 124 # look! binary contents, and a binary property! 125 expected_disk = svntest.main.greek_state.copy() 126 expected_disk.add({ 127 'A/theta' : Item(theta_contents_local, 128 props={'svn:mime-type' : 'application/octet-stream'}), 129 }) 130 131 # Create expected status tree for the update. 132 expected_status = svntest.actions.get_virginal_state(wc_backup, 3) 133 expected_status.add({ 134 'A/theta' : Item(status='C ', wc_rev=3), 135 }) 136 137 extra_files = ['theta.r2', 'theta.r3'] 138 139 # Do the update and check the results in three ways. Pass our 140 # custom singleton handler to verify the .orig file; this handler 141 # will verify the existence (and contents) of both binary files 142 # after the update finishes. 143 svntest.actions.run_and_verify_update(wc_backup, 144 expected_output, 145 expected_disk, 146 expected_status, 147 [], True, 148 extra_files=extra_files) 149 150#---------------------------------------------------------------------- 151 152def update_binary_file_2(sbox): 153 "update to an old revision of a binary files" 154 155 sbox.build() 156 wc_dir = sbox.wc_dir 157 158 # Suck up contents of a test .png file. 159 theta_contents = open(os.path.join(sys.path[0], "theta.bin"), 'rb').read() 160 161 # 102400 is svn_txdelta_window_size. We're going to make sure we 162 # have at least 102401 bytes of data in our second binary file (for 163 # no reason other than we have had problems in the past with getting 164 # svndiff data out of the repository for files > 102400 bytes). 165 # How? Well, we'll just keep doubling the binary contents of the 166 # original theta.png until we're big enough. 167 zeta_contents = theta_contents 168 while(len(zeta_contents) < 102401): 169 zeta_contents = zeta_contents + zeta_contents 170 171 # Write our two files' contents out to disk, in A/theta and A/zeta. 172 theta_path = sbox.ospath('A/theta') 173 svntest.main.file_write(theta_path, theta_contents, 'wb') 174 zeta_path = sbox.ospath('A/zeta') 175 svntest.main.file_write(zeta_path, zeta_contents, 'wb') 176 177 # Now, `svn add' those two files. 178 svntest.main.run_svn(None, 'add', theta_path, zeta_path) 179 180 # Created expected output tree for 'svn ci' 181 expected_output = svntest.wc.State(wc_dir, { 182 'A/theta' : Item(verb='Adding (bin)'), 183 'A/zeta' : Item(verb='Adding (bin)'), 184 }) 185 186 # Create expected status tree 187 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 188 expected_status.add({ 189 'A/theta' : Item(status=' ', wc_rev=2), 190 'A/zeta' : Item(status=' ', wc_rev=2), 191 }) 192 193 # Commit the new binary filea, creating revision 2. 194 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 195 expected_status) 196 197 # Make some mods to the binary files. 198 svntest.main.file_append(theta_path, "foobar") 199 new_theta_contents = theta_contents + b"foobar" 200 svntest.main.file_append(zeta_path, "foobar") 201 new_zeta_contents = zeta_contents + b"foobar" 202 203 # Created expected output tree for 'svn ci' 204 expected_output = svntest.wc.State(wc_dir, { 205 'A/theta' : Item(verb='Sending'), 206 'A/zeta' : Item(verb='Sending'), 207 }) 208 209 # Create expected status tree 210 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 211 expected_status.add({ 212 'A/theta' : Item(status=' ', wc_rev=3), 213 'A/zeta' : Item(status=' ', wc_rev=3), 214 }) 215 216 # Commit original working copy again, creating revision 3. 217 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 218 expected_status) 219 220 # Create expected output tree for an update to rev 2. 221 expected_output = svntest.wc.State(wc_dir, { 222 'A/theta' : Item(status='U '), 223 'A/zeta' : Item(status='U '), 224 }) 225 226 # Create expected disk tree for the update -- 227 # look! binary contents, and a binary property! 228 expected_disk = svntest.main.greek_state.copy() 229 expected_disk.add({ 230 'A/theta' : Item(theta_contents, 231 props={'svn:mime-type' : 'application/octet-stream'}), 232 'A/zeta' : Item(zeta_contents, 233 props={'svn:mime-type' : 'application/octet-stream'}), 234 }) 235 236 # Create expected status tree for the update. 237 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 238 expected_status.add({ 239 'A/theta' : Item(status=' ', wc_rev=2), 240 'A/zeta' : Item(status=' ', wc_rev=2), 241 }) 242 243 # Do an update from revision 2 and make sure that our binary file 244 # gets reverted to its original contents. 245 svntest.actions.run_and_verify_update(wc_dir, 246 expected_output, 247 expected_disk, 248 expected_status, 249 [], True, 250 '-r', '2', wc_dir) 251 252 253#---------------------------------------------------------------------- 254 255@Issue(4128) 256def update_binary_file_3(sbox): 257 "update locally modified file to equal versions" 258 259 sbox.build() 260 wc_dir = sbox.wc_dir 261 262 # Suck up contents of a test .png file. 263 theta_contents = open(os.path.join(sys.path[0], "theta.bin"), 'rb').read() 264 265 # Write our files contents out to disk, in A/theta. 266 theta_path = sbox.ospath('A/theta') 267 svntest.main.file_write(theta_path, theta_contents, 'wb') 268 269 # Now, `svn add' that file. 270 svntest.main.run_svn(None, 'add', theta_path) 271 272 # Created expected output tree for 'svn ci' 273 expected_output = svntest.wc.State(wc_dir, { 274 'A/theta' : Item(verb='Adding (bin)'), 275 }) 276 277 # Create expected status tree 278 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 279 expected_status.add({ 280 'A/theta' : Item(status=' ', wc_rev=2), 281 }) 282 283 # Commit the new binary file, creating revision 2. 284 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 285 expected_status) 286 287 # Make some mods to the binary files. 288 svntest.main.file_append(theta_path, "foobar") 289 new_theta_contents = theta_contents + b"foobar" 290 291 # Created expected output tree for 'svn ci' 292 expected_output = svntest.wc.State(wc_dir, { 293 'A/theta' : Item(verb='Sending'), 294 }) 295 296 # Create expected status tree 297 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 298 expected_status.add({ 299 'A/theta' : Item(status=' ', wc_rev=3), 300 }) 301 302 # Commit modified working copy, creating revision 3. 303 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 304 expected_status) 305 306 # Now we locally modify the file back to the old version. 307 svntest.main.file_write(theta_path, theta_contents, 'wb') 308 309 # Create expected output tree for an update to rev 2. 310 expected_output = svntest.wc.State(wc_dir, { 311 'A/theta' : Item(status='G '), 312 }) 313 314 # Create expected disk tree for the update 315 expected_disk = svntest.main.greek_state.copy() 316 expected_disk.add({ 317 'A/theta' : Item(theta_contents, 318 props={'svn:mime-type' : 'application/octet-stream'}), 319 }) 320 321 # Create expected status tree for the update. 322 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 323 expected_status.add({ 324 'A/theta' : Item(status=' ', wc_rev=2), 325 }) 326 327 # Do an update from revision 2 and make sure that our binary file 328 # gets reverted to its original contents. 329 # This used to raise a conflict. 330 svntest.actions.run_and_verify_update(wc_dir, 331 expected_output, 332 expected_disk, 333 expected_status, 334 [], True, 335 '-r', '2', wc_dir) 336 337#---------------------------------------------------------------------- 338 339def update_missing(sbox): 340 "update missing items (by name) in working copy" 341 342 sbox.build() 343 wc_dir = sbox.wc_dir 344 345 # Remove some files and dirs from the working copy. 346 mu_path = sbox.ospath('A/mu') 347 rho_path = sbox.ospath('A/D/G/rho') 348 E_path = sbox.ospath('A/B/E') 349 H_path = sbox.ospath('A/D/H') 350 351 # remove two files to verify that they get restored 352 os.remove(mu_path) 353 os.remove(rho_path) 354 355 ### FIXME I think directories work because they generate 'A' 356 ### feedback, is this the correct feedback? 357 svntest.main.safe_rmtree(E_path) 358 svntest.main.safe_rmtree(H_path) 359 360 # In single-db mode all missing items will just be restored 361 A_or_Restored = Item(verb='Restored') 362 363 # Create expected output tree for an update of the missing items by name 364 expected_output = svntest.wc.State(wc_dir, { 365 'A/mu' : Item(verb='Restored'), 366 'A/D/G/rho' : Item(verb='Restored'), 367 'A/B/E' : A_or_Restored, 368 'A/B/E/alpha' : A_or_Restored, 369 'A/B/E/beta' : A_or_Restored, 370 'A/D/H' : A_or_Restored, 371 'A/D/H/chi' : A_or_Restored, 372 'A/D/H/omega' : A_or_Restored, 373 'A/D/H/psi' : A_or_Restored, 374 }) 375 376 # Create expected disk tree for the update. 377 expected_disk = svntest.main.greek_state.copy() 378 379 # Create expected status tree for the update. 380 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 381 382 # Do the update and check the results in three ways. 383 svntest.actions.run_and_verify_update(wc_dir, 384 expected_output, 385 expected_disk, 386 expected_status, 387 [], False, 388 mu_path, rho_path, 389 E_path, H_path) 390 391#---------------------------------------------------------------------- 392 393def update_ignores_added(sbox): 394 "update should not munge adds or replaces" 395 396 sbox.build() 397 wc_dir = sbox.wc_dir 398 399 # Commit something so there's actually a new revision to update to. 400 rho_path = sbox.ospath('A/D/G/rho') 401 svntest.main.file_append(rho_path, "More stuff in rho.\n") 402 svntest.main.run_svn(None, 403 'ci', '-m', 'log msg', rho_path) 404 405 # Create a new file, 'zeta', and schedule it for addition. 406 zeta_path = sbox.ospath('A/B/zeta') 407 svntest.main.file_append(zeta_path, "This is the file 'zeta'.\n") 408 svntest.main.run_svn(None, 'add', zeta_path) 409 410 # Schedule another file, say, 'gamma', for replacement. 411 gamma_path = sbox.ospath('A/D/gamma') 412 svntest.main.run_svn(None, 'delete', gamma_path) 413 svntest.main.file_append(gamma_path, "This is a new 'gamma' now.\n") 414 svntest.main.run_svn(None, 'add', gamma_path) 415 416 # Now update. "zeta at revision 0" should *not* be reported at all, 417 # so it should remain scheduled for addition at revision 0. gamma 418 # was scheduled for replacement, so it also should remain marked as 419 # such, and maintain its revision of 1. 420 421 # Create expected output tree for an update of the wc_backup. 422 expected_output = svntest.wc.State(wc_dir, { }) 423 424 # Create expected disk tree for the update. 425 expected_disk = svntest.main.greek_state.copy() 426 expected_disk.add({ 427 'A/B/zeta' : Item("This is the file 'zeta'.\n"), 428 }) 429 expected_disk.tweak('A/D/gamma', contents="This is a new 'gamma' now.\n") 430 expected_disk.tweak('A/D/G/rho', 431 contents="This is the file 'rho'.\nMore stuff in rho.\n") 432 433 # Create expected status tree for the update. 434 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 435 436 # Before WC-NG we couldn't bump the wc_rev for gamma from 1 to 2 because it could 437 # be replaced with history and we couldn't store all the revision information. 438 # WC-NG just bumps the revision as it can easily store different revisions. 439 expected_status.tweak('A/D/gamma', wc_rev=2, status='R ') 440 expected_status.add({ 441 'A/B/zeta' : Item(status='A ', wc_rev=0), 442 }) 443 444 # Do the update and check the results in three ways. 445 svntest.actions.run_and_verify_update(wc_dir, 446 expected_output, 447 expected_disk, 448 expected_status) 449 450 451#---------------------------------------------------------------------- 452 453def update_to_rev_zero(sbox): 454 "update to revision 0" 455 456 sbox.build() 457 wc_dir = sbox.wc_dir 458 459 iota_path = sbox.ospath('iota') 460 A_path = sbox.ospath('A') 461 462 # Create expected output tree for an update to rev 0 463 expected_output = svntest.wc.State(wc_dir, { 464 'iota' : Item(status='D '), 465 'A' : Item(status='D '), 466 }) 467 468 # Create expected disk tree for the update to rev 0 469 expected_disk = svntest.wc.State(wc_dir, { }) 470 471 # Do the update and check the results. 472 svntest.actions.run_and_verify_update(wc_dir, 473 expected_output, 474 expected_disk, 475 None, [], False, 476 '-r', '0', wc_dir) 477 478#---------------------------------------------------------------------- 479 480def receive_overlapping_same_change(sbox): 481 "overlapping identical changes should not conflict" 482 483 ### (See https://issues.apache.org/jira/browse/SVN-682.) 484 ### 485 ### How this test works: 486 ### 487 ### Create working copy foo, modify foo/iota. Duplicate foo, 488 ### complete with locally modified iota, to bar. Now we should 489 ### have: 490 ### 491 ### $ svn st foo 492 ### M foo/iota 493 ### $ svn st bar 494 ### M bar/iota 495 ### $ 496 ### 497 ### Commit the change from foo, then update bar. The repository 498 ### change should get folded into bar/iota with no conflict, since 499 ### the two modifications are identical. 500 501 sbox.build() 502 wc_dir = sbox.wc_dir 503 504 # Modify iota. 505 iota_path = sbox.ospath('iota') 506 svntest.main.file_append(iota_path, "A change to iota.\n") 507 508 # Duplicate locally modified wc, giving us the "other" wc. 509 other_wc = sbox.add_wc_path('other') 510 svntest.actions.duplicate_dir(wc_dir, other_wc) 511 other_iota_path = os.path.join(other_wc, 'iota') 512 513 # Created expected output tree for 'svn ci' 514 expected_output = svntest.wc.State(wc_dir, { 515 'iota' : Item(verb='Sending'), 516 }) 517 518 # Create expected status tree 519 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 520 expected_status.tweak('iota', wc_rev=2) 521 522 # Commit the change, creating revision 2. 523 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 524 expected_status) 525 526 # Expected output tree for update of other_wc. 527 expected_output = svntest.wc.State(other_wc, { 528 'iota' : Item(status='G '), 529 }) 530 531 # Expected disk tree for the update. 532 expected_disk = svntest.main.greek_state.copy() 533 expected_disk.tweak('iota', 534 contents="This is the file 'iota'.\nA change to iota.\n") 535 536 # Expected status tree for the update. 537 expected_status = svntest.actions.get_virginal_state(other_wc, 2) 538 539 # Do the update and check the results in three ways. 540 svntest.actions.run_and_verify_update(other_wc, 541 expected_output, 542 expected_disk, 543 expected_status) 544 545#---------------------------------------------------------------------- 546 547def update_to_resolve_text_conflicts(sbox): 548 "delete files and update to resolve text conflicts" 549 550 sbox.build() 551 wc_dir = sbox.wc_dir 552 553 # Make a backup copy of the working copy 554 wc_backup = sbox.add_wc_path('backup') 555 svntest.actions.duplicate_dir(wc_dir, wc_backup) 556 557 # Make a couple of local mods to files which will be committed 558 mu_path = sbox.ospath('A/mu') 559 rho_path = sbox.ospath('A/D/G/rho') 560 svntest.main.file_append(mu_path, 'Original appended text for mu\n') 561 svntest.main.file_append(rho_path, 'Original appended text for rho\n') 562 svntest.main.run_svn(None, 'propset', 'Kubla', 'Khan', rho_path) 563 564 # Make a couple of local mods to files which will be conflicted 565 mu_path_backup = os.path.join(wc_backup, 'A', 'mu') 566 rho_path_backup = os.path.join(wc_backup, 'A', 'D', 'G', 'rho') 567 svntest.main.file_append(mu_path_backup, 568 'Conflicting appended text for mu\n') 569 svntest.main.file_append(rho_path_backup, 570 'Conflicting appended text for rho\n') 571 svntest.main.run_svn(None, 'propset', 'Kubla', 'Xanadu', rho_path_backup) 572 573 # Created expected output tree for 'svn ci' 574 expected_output = svntest.wc.State(wc_dir, { 575 'A/mu' : Item(verb='Sending'), 576 'A/D/G/rho' : Item(verb='Sending'), 577 }) 578 579 # Create expected status tree; all local revisions should be at 1, 580 # but mu and rho should be at revision 2. 581 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 582 expected_status.tweak('A/mu', wc_rev=2) 583 expected_status.tweak('A/D/G/rho', wc_rev=2, status=' ') 584 585 # Commit. 586 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 587 expected_status) 588 589 # Create expected output tree for an update of the wc_backup. 590 expected_output = svntest.wc.State(wc_backup, { 591 'A/mu' : Item(status='C '), 592 'A/D/G/rho' : Item(status='CC'), 593 }) 594 595 # Create expected disk tree for the update. 596 expected_disk = svntest.main.greek_state.copy() 597 expected_disk.tweak('A/mu', 598 contents="\n".join(["This is the file 'mu'.", 599 "<<<<<<< .mine", 600 "Conflicting appended text for mu", 601 "||||||| .r1", 602 "=======", 603 "Original appended text for mu", 604 ">>>>>>> .r2", 605 ""])) 606 expected_disk.tweak('A/D/G/rho', 607 contents="\n".join(["This is the file 'rho'.", 608 "<<<<<<< .mine", 609 "Conflicting appended text for rho", 610 "||||||| .r1", 611 "=======", 612 "Original appended text for rho", 613 ">>>>>>> .r2", 614 ""])) 615 616 # Create expected status tree for the update. 617 expected_status = svntest.actions.get_virginal_state(wc_backup, 2) 618 expected_status.tweak('A/mu', status='C ') 619 expected_status.tweak('A/D/G/rho', status='CC') 620 621 # "Extra" files that we expect to result from the conflicts. 622 # These are expressed as list of regexps. What a cool system! :-) 623 extra_files = ['mu.*\.r1', 'mu.*\.r2', 'mu.*\.mine', 624 'rho.*\.r1', 'rho.*\.r2', 'rho.*\.mine', 'rho.*\.prej'] 625 626 # Do the update and check the results in three ways. 627 # All "extra" files are passed to detect_conflict_files(). 628 svntest.actions.run_and_verify_update(wc_backup, 629 expected_output, 630 expected_disk, 631 expected_status, 632 extra_files=extra_files) 633 634 # remove the conflicting files to clear text conflict but not props conflict 635 os.remove(mu_path_backup) 636 os.remove(rho_path_backup) 637 638 ### TODO: Can't get run_and_verify_update to work here :-( I get 639 # the error "Unequal Types: one Node is a file, the other is a 640 # directory". Use run_svn and then run_and_verify_status instead 641 exit_code, stdout_lines, stdout_lines = svntest.main.run_svn(None, 'up', 642 wc_backup) 643 if len (stdout_lines) > 0: 644 logger.warn("update 2 failed") 645 raise svntest.Failure 646 647 # Create expected status tree 648 expected_status = svntest.actions.get_virginal_state(wc_backup, 2) 649 expected_status.tweak('A/D/G/rho', status=' C') 650 651 svntest.actions.run_and_verify_status(wc_backup, expected_status) 652 653#---------------------------------------------------------------------- 654 655def update_delete_modified_files(sbox): 656 "update that deletes modified files" 657 658 sbox.build() 659 wc_dir = sbox.wc_dir 660 661 # Delete a file 662 alpha_path = sbox.ospath('A/B/E/alpha') 663 svntest.actions.run_and_verify_svn(None, [], 664 'rm', alpha_path) 665 666 # Delete a directory containing files 667 G_path = sbox.ospath('A/D/G') 668 svntest.actions.run_and_verify_svn(None, [], 669 'rm', G_path) 670 671 # Commit 672 svntest.actions.run_and_verify_svn(None, [], 673 'ci', '-m', 'log msg', wc_dir) 674 675 ### Update before backdating to avoid obstructed update error for G 676 svntest.actions.run_and_verify_svn(None, [], 677 'up', wc_dir) 678 679 # Backdate to restore deleted items 680 svntest.actions.run_and_verify_svn(None, [], 681 'up', '-r', '1', wc_dir) 682 683 # Modify the file to be deleted, and a file in the directory to be deleted 684 svntest.main.file_append(alpha_path, 'appended alpha text\n') 685 pi_path = os.path.join(G_path, 'pi') 686 svntest.main.file_append(pi_path, 'appended pi text\n') 687 688 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 689 expected_status.tweak('A/B/E/alpha', 'A/D/G/pi', status='M ') 690 691 svntest.actions.run_and_verify_status(wc_dir, expected_status) 692 693 # Now update to 'delete' modified items -- that is, remove them from 694 # version control, but leave them on disk. It used to be we would 695 # expect an 'obstructed update' error (see issue #1196), then we 696 # expected success (see issue #1806), and now we expect tree conflicts 697 # (see issue #2282) on the missing or unversioned items. 698 expected_output = svntest.wc.State(wc_dir, { 699 'A/B/E/alpha' : Item(status=' ', treeconflict='C'), 700 'A/D/G' : Item(status=' ', treeconflict='C'), 701 }) 702 703 expected_disk = svntest.main.greek_state.copy() 704 expected_disk.tweak('A/B/E/alpha', 705 contents=\ 706 "This is the file 'alpha'.\nappended alpha text\n") 707 expected_disk.tweak('A/D/G/pi', 708 contents=\ 709 "This is the file 'pi'.\nappended pi text\n") 710 711 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 712 # A/B/E/alpha and the subtree rooted at A/D/G had local modificiations 713 # prior to the update. So there is a tree conflict and both A/B/E/alpha 714 # A/D/G remain after the update, scheduled for addition as copies of 715 # themselves from r1, along with the local modifications. 716 expected_status.tweak('A/B/E/alpha', status='A ', copied='+', wc_rev='-', 717 treeconflict='C') 718 expected_status.tweak('A/D/G/pi', status='M ') 719 expected_status.tweak('A/D/G/pi', status='M ', copied='+', wc_rev='-') 720 expected_status.tweak('A/D/G/rho', 'A/D/G/tau', status=' ', copied='+', 721 wc_rev='-') 722 expected_status.tweak('A/D/G', status='A ', copied='+', wc_rev='-', 723 treeconflict='C') 724 725 svntest.actions.run_and_verify_update(wc_dir, 726 expected_output, 727 expected_disk, 728 expected_status) 729 730#---------------------------------------------------------------------- 731 732# Issue 847. Doing an add followed by a remove for an item in state 733# "deleted" caused the "deleted" state to get forgotten 734 735def update_after_add_rm_deleted(sbox): 736 "update after add/rm of deleted state" 737 738 sbox.build() 739 wc_dir = sbox.wc_dir 740 741 # Delete a file and directory from WC 742 alpha_path = sbox.ospath('A/B/E/alpha') 743 F_path = sbox.ospath('A/B/F') 744 svntest.actions.run_and_verify_svn(None, [], 'rm', alpha_path, F_path) 745 746 # Commit deletion 747 expected_output = svntest.wc.State(wc_dir, { 748 'A/B/E/alpha' : Item(verb='Deleting'), 749 'A/B/F' : Item(verb='Deleting'), 750 }) 751 752 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 753 expected_status.remove('A/B/E/alpha') 754 expected_status.remove('A/B/F') 755 756 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 757 expected_status) 758 759 # alpha and F are now in state "deleted", next we add a new ones 760 svntest.main.file_append(alpha_path, "new alpha") 761 svntest.actions.run_and_verify_svn(None, [], 'add', alpha_path) 762 763 svntest.actions.run_and_verify_svn(None, [], 'mkdir', F_path) 764 765 # New alpha and F should be in add state A 766 expected_status.add({ 767 'A/B/E/alpha' : Item(status='A ', wc_rev=0), 768 'A/B/F' : Item(status='A ', wc_rev=0), 769 }) 770 771 svntest.actions.run_and_verify_status(wc_dir, expected_status) 772 773 # Forced removal of new alpha and F must restore "deleted" state 774 775 svntest.actions.run_and_verify_svn(None, [], 'rm', '--force', 776 alpha_path, F_path) 777 if os.path.exists(alpha_path) or os.path.exists(F_path): 778 raise svntest.Failure 779 780 # "deleted" state is not visible in status 781 expected_status.remove('A/B/E/alpha', 'A/B/F') 782 783 svntest.actions.run_and_verify_status(wc_dir, expected_status) 784 785 # Although parent dir is already at rev 1, the "deleted" state will cause 786 # alpha and F to be restored in the WC when updated to rev 1 787 svntest.actions.run_and_verify_svn(None, [], 'up', '-r', '1', wc_dir) 788 789 expected_status.add({ 790 'A/B/E/alpha' : Item(status=' ', wc_rev=1), 791 'A/B/F' : Item(status=' ', wc_rev=1), 792 }) 793 794 svntest.actions.run_and_verify_status(wc_dir, expected_status) 795 796#---------------------------------------------------------------------- 797 798# Issue 1591. Updating a working copy which contains local 799# obstructions marks a directory as incomplete. Removal of the 800# obstruction and subsequent update should clear the "incomplete" 801# flag. 802 803def obstructed_update_alters_wc_props(sbox): 804 "obstructed update alters WC properties" 805 806 sbox.build() 807 wc_dir = sbox.wc_dir 808 809 # Create a new dir in the repo in prep for creating an obstruction. 810 #print "Adding dir to repo" 811 svntest.actions.run_and_verify_svn(None, [], 812 'mkdir', '-m', 813 'prep for obstruction', 814 sbox.repo_url + '/A/foo') 815 816 # Create an obstruction, a file in the WC with the same name as 817 # present in a newer rev of the repo. 818 #print "Creating obstruction" 819 obstruction_parent_path = sbox.ospath('A') 820 obstruction_path = os.path.join(obstruction_parent_path, 'foo') 821 svntest.main.file_append(obstruction_path, 'an obstruction') 822 823 # Update the WC to that newer rev to trigger the obstruction. 824 #print "Updating WC" 825 # svntest.factory.make(sbox, 'svn update') 826 # exit(0) 827 expected_output = svntest.wc.State(wc_dir, { 828 'A/foo' : Item(status=' ', treeconflict='C'), 829 }) 830 831 expected_disk = svntest.main.greek_state.copy() 832 expected_disk.add({ 833 'A/foo' : Item(contents="an obstruction"), 834 }) 835 836 expected_status = actions.get_virginal_state(wc_dir, 2) 837 expected_status.add({ 838 'A/foo' : Item(status='D ', treeconflict='C', wc_rev=2), 839 }) 840 841 actions.run_and_verify_update(wc_dir, expected_output, expected_disk, 842 expected_status) 843 844 845 # Remove the file which caused the obstruction. 846 #print "Removing obstruction" 847 os.unlink(obstruction_path) 848 849 svntest.main.run_svn(None, 'revert', obstruction_path) 850 851 # Update the -- now unobstructed -- WC again. 852 #print "Updating WC again" 853 expected_output = svntest.wc.State(wc_dir, { 854 }) 855 856 expected_disk = svntest.main.greek_state.copy() 857 expected_disk.add({ 858 'A/foo' : Item(), 859 }) 860 861 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 862 expected_status.add({ 863 'A/foo' : Item(status=' ', wc_rev=2), 864 }) 865 866 svntest.actions.run_and_verify_update(wc_dir, 867 expected_output, 868 expected_disk, 869 expected_status) 870 871 # The previously obstructed resource should now be in the WC. 872 if not os.path.isdir(obstruction_path): 873 raise svntest.Failure 874 875#---------------------------------------------------------------------- 876 877# Issue 938. 878def update_replace_dir(sbox): 879 "update that replaces a directory" 880 881 sbox.build() 882 wc_dir = sbox.wc_dir 883 884 # Delete a directory 885 F_path = sbox.ospath('A/B/F') 886 svntest.actions.run_and_verify_svn(None, [], 'rm', F_path) 887 888 # Commit deletion 889 expected_output = svntest.wc.State(wc_dir, { 890 'A/B/F' : Item(verb='Deleting'), 891 }) 892 893 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 894 expected_status.remove('A/B/F') 895 896 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 897 expected_status) 898 899 # Add replacement directory 900 svntest.actions.run_and_verify_svn(None, [], 'mkdir', F_path) 901 902 # Commit addition 903 expected_output = svntest.wc.State(wc_dir, { 904 'A/B/F' : Item(verb='Adding'), 905 }) 906 907 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 908 expected_status.tweak('A/B/F', wc_rev=3) 909 910 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 911 expected_status) 912 913 # Update to HEAD 914 expected_output = svntest.wc.State(wc_dir, { 915 }) 916 917 expected_disk = svntest.main.greek_state.copy() 918 919 expected_status = svntest.actions.get_virginal_state(wc_dir, 3) 920 921 svntest.actions.run_and_verify_update(wc_dir, 922 expected_output, 923 expected_disk, 924 expected_status) 925 926 # Update to revision 1 replaces the directory 927 expected_output = svntest.wc.State(wc_dir, { 928 'A/B/F' : Item(status='A ', prev_status='D '), 929 }) 930 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 931 svntest.actions.run_and_verify_update(wc_dir, 932 expected_output, 933 expected_disk, 934 expected_status, 935 [], False, 936 '-r', '1', wc_dir) 937 938 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 939 940 svntest.actions.run_and_verify_status(wc_dir, expected_status) 941 942#---------------------------------------------------------------------- 943 944def update_single_file(sbox): 945 "update with explicit file target" 946 947 sbox.build() 948 wc_dir = sbox.wc_dir 949 950 expected_disk = svntest.main.greek_state.copy() 951 952 # Make a local mod to a file which will be committed 953 mu_path = sbox.ospath('A/mu') 954 svntest.main.file_append(mu_path, '\nAppended text for mu') 955 956 # Commit. 957 expected_output = svntest.wc.State(wc_dir, { 958 'A/mu' : Item(verb='Sending'), 959 }) 960 961 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 962 expected_status.tweak('A/mu', wc_rev=2) 963 964 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 965 expected_status) 966 967 # At one stage 'svn up file' failed with a parent lock error 968 was_cwd = os.getcwd() 969 os.chdir(sbox.ospath('A')) 970 971 ### Can't get run_and_verify_update to work having done the chdir. 972 svntest.actions.run_and_verify_svn(None, [], 973 'up', '-r', '1', 'mu') 974 os.chdir(was_cwd) 975 976 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 977 978 svntest.actions.run_and_verify_status(wc_dir, expected_status) 979 980#---------------------------------------------------------------------- 981def prop_update_on_scheduled_delete(sbox): 982 "receive prop update to file scheduled for deletion" 983 984 sbox.build() 985 wc_dir = sbox.wc_dir 986 987 other_wc = sbox.add_wc_path('other') 988 989 # Make the "other" working copy. 990 svntest.actions.duplicate_dir(wc_dir, other_wc) 991 992 iota_path = sbox.ospath('iota') 993 other_iota_path = os.path.join(other_wc, 'iota') 994 995 svntest.main.run_svn(None, 'propset', 'foo', 'bar', iota_path) 996 997 # Created expected output tree for 'svn ci' 998 expected_output = svntest.wc.State(wc_dir, { 999 'iota' : Item(verb='Sending'), 1000 }) 1001 1002 # Create expected status tree 1003 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 1004 expected_status.tweak('iota', wc_rev=2) 1005 1006 # Commit the change, creating revision 2. 1007 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 1008 expected_status) 1009 1010 svntest.main.run_svn(None, 'rm', other_iota_path) 1011 1012 # Expected output tree for update of other_wc. 1013 expected_output = svntest.wc.State(other_wc, { 1014 'iota' : Item(status=' ', treeconflict='C'), 1015 }) 1016 1017 # Expected disk tree for the update. 1018 expected_disk = svntest.main.greek_state.copy() 1019 expected_disk.remove('iota') 1020 1021 # Expected status tree for the update. 1022 expected_status = svntest.actions.get_virginal_state(other_wc, 2) 1023 expected_status.tweak('iota', status='D ', treeconflict='C') 1024 1025 # Do the update and check the results in three ways. 1026 svntest.actions.run_and_verify_update(other_wc, 1027 expected_output, 1028 expected_disk, 1029 expected_status) 1030 1031#---------------------------------------------------------------------- 1032 1033def update_receive_illegal_name(sbox): 1034 "bail when receive a file or dir named .svn" 1035 1036 sbox.build() 1037 wc_dir = sbox.wc_dir 1038 1039 # This tests the revision 4334 fix for issue #1068. 1040 1041 legal_url = sbox.repo_url + '/A/D/G/svn' 1042 illegal_url = (sbox.repo_url 1043 + '/A/D/G/' + svntest.main.get_admin_name()) 1044 # Ha! The client doesn't allow us to mkdir a '.svn' but it does 1045 # allow us to copy to a '.svn' so ... 1046 svntest.actions.run_and_verify_svn(None, [], 1047 'mkdir', '-m', 'log msg', 1048 legal_url) 1049 svntest.actions.run_and_verify_svn(None, [], 1050 'mv', '-m', 'log msg', 1051 legal_url, illegal_url) 1052 1053 # Do the update twice, both should fail. After the first failure 1054 # the wc will be marked "incomplete". 1055 for n in range(2): 1056 exit_code, out, err = svntest.main.run_svn(1, 'up', wc_dir) 1057 for line in err: 1058 if line.find("of the same name") != -1: 1059 break 1060 else: 1061 raise svntest.Failure 1062 1063 # At one stage an obstructed update in an incomplete wc would leave 1064 # a txn behind 1065 exit_code, out, err = svntest.main.run_svnadmin('lstxns', sbox.repo_dir) 1066 if out or err: 1067 raise svntest.Failure 1068 1069#---------------------------------------------------------------------- 1070 1071def update_deleted_missing_dir(sbox): 1072 "update missing dir to rev in which it is absent" 1073 1074 sbox.build() 1075 wc_dir = sbox.wc_dir 1076 1077 E_path = sbox.ospath('A/B/E') 1078 H_path = sbox.ospath('A/D/H') 1079 1080 # Create a new revision with directories deleted 1081 svntest.main.run_svn(None, 'rm', E_path) 1082 svntest.main.run_svn(None, 'rm', H_path) 1083 svntest.main.run_svn(None, 1084 'ci', '-m', 'log msg', E_path, H_path) 1085 1086 # Update back to the old revision 1087 svntest.main.run_svn(None, 1088 'up', '-r', '1', wc_dir) 1089 1090 # Delete the directories from disk 1091 svntest.main.safe_rmtree(E_path) 1092 svntest.main.safe_rmtree(H_path) 1093 1094 # Create expected output tree for an update of the missing items by name 1095 expected_output = svntest.wc.State(wc_dir, { 1096 'A/D/H/psi' : Item(verb='Restored'), 1097 'A/D/H/omega' : Item(verb='Restored'), 1098 'A/D/H/chi' : Item(verb='Restored'), 1099 'A/B/E/beta' : Item(verb='Restored'), 1100 'A/B/E/alpha' : Item(verb='Restored'), 1101 # A/B/E and A/D/H are also restored, but are then overriden by the delete 1102 'A/B/E' : Item(status='D ', prev_verb='Restored'), 1103 'A/D/H' : Item(status='D ', prev_verb='Restored'), 1104 }) 1105 1106 # Create expected disk tree for the update. 1107 expected_disk = svntest.main.greek_state.copy() 1108 expected_disk.remove('A/B/E', 'A/B/E/alpha', 'A/B/E/beta') 1109 expected_disk.remove('A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi') 1110 1111 # Create expected status tree for the update. 1112 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 1113 expected_status.remove('A/B/E', 'A/B/E/alpha', 'A/B/E/beta') 1114 expected_status.remove('A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi') 1115 1116 # Do the update, specifying the deleted paths explicitly. 1117 svntest.actions.run_and_verify_update(wc_dir, 1118 expected_output, 1119 expected_disk, 1120 expected_status, 1121 [], False, 1122 "-r", "2", E_path, H_path) 1123 1124 # Update back to the old revision again 1125 svntest.main.run_svn(None, 1126 'up', '-r', '1', wc_dir) 1127 1128 # This time we're updating the whole working copy 1129 expected_status.tweak(wc_rev=2) 1130 1131 # And now we don't expect restore operations 1132 expected_output = svntest.wc.State(wc_dir, { 1133 'A/B/E' : Item(status='D '), 1134 'A/D/H' : Item(status='D '), 1135 }) 1136 1137 # Do the update, on the whole working copy this time 1138 svntest.actions.run_and_verify_update(wc_dir, 1139 expected_output, 1140 expected_disk, 1141 expected_status, 1142 [], False, 1143 "-r", "2", wc_dir) 1144 1145#---------------------------------------------------------------------- 1146 1147# Issue 919. This test was written as a regression test for "item 1148# should remain 'deleted' when an update deletes a sibling". 1149def another_hudson_problem(sbox): 1150 "another \"hudson\" problem: updates that delete" 1151 1152 sbox.build() 1153 wc_dir = sbox.wc_dir 1154 1155 # Delete/commit gamma thus making it 'deleted' 1156 gamma_path = sbox.ospath('A/D/gamma') 1157 svntest.main.run_svn(None, 'rm', gamma_path) 1158 1159 expected_output = svntest.wc.State(wc_dir, { 1160 'A/D/gamma' : Item(verb='Deleting'), 1161 }) 1162 1163 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 1164 expected_status.remove('A/D/gamma') 1165 1166 svntest.actions.run_and_verify_commit(wc_dir, 1167 expected_output, 1168 expected_status) 1169 1170 # Delete directory G from the repository 1171 svntest.actions.run_and_verify_svn(['Committing transaction...\n', 1172 'Committed revision 3.\n'], [], 1173 'rm', '-m', 'log msg', 1174 sbox.repo_url + '/A/D/G') 1175 1176 # Remove corresponding tree from working copy 1177 G_path = sbox.ospath('A/D/G') 1178 svntest.main.safe_rmtree(G_path) 1179 1180 # Update missing directory to receive the delete, this should mark G 1181 # as 'deleted' and should not alter gamma's entry. 1182 1183 expected_output = ["Updating '%s':\n" % (G_path), 1184 'Restored \'' + G_path + '\'\n', 1185 'Restored \'' + G_path + os.path.sep + 'pi\'\n', 1186 'Restored \'' + G_path + os.path.sep + 'rho\'\n', 1187 'Restored \'' + G_path + os.path.sep + 'tau\'\n', 1188 'D '+G_path+'\n', 1189 'Updated to revision 3.\n', 1190 ] 1191 1192 # Sigh, I can't get run_and_verify_update to work (but not because 1193 # of issue 919 as far as I can tell) 1194 expected_output = svntest.verify.UnorderedOutput(expected_output) 1195 svntest.actions.run_and_verify_svn(expected_output, [], 1196 'up', G_path) 1197 1198 # Both G and gamma should be 'deleted', update should produce no output 1199 expected_status = svntest.actions.get_virginal_state(wc_dir, 3) 1200 expected_status.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau', 1201 'A/D/gamma') 1202 1203 expected_disk = svntest.main.greek_state.copy() 1204 expected_disk.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau', 1205 'A/D/gamma') 1206 1207 svntest.actions.run_and_verify_update(wc_dir, 1208 "", 1209 expected_disk, 1210 expected_status) 1211 1212#---------------------------------------------------------------------- 1213def update_deleted_targets(sbox): 1214 "explicit update of deleted=true targets" 1215 1216 sbox.build() 1217 wc_dir = sbox.wc_dir 1218 1219 # Delete/commit thus creating 'deleted=true' entries 1220 gamma_path = sbox.ospath('A/D/gamma') 1221 F_path = sbox.ospath('A/B/F') 1222 svntest.main.run_svn(None, 'rm', gamma_path, F_path) 1223 1224 expected_output = svntest.wc.State(wc_dir, { 1225 'A/D/gamma' : Item(verb='Deleting'), 1226 'A/B/F' : Item(verb='Deleting'), 1227 }) 1228 1229 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 1230 expected_status.remove('A/D/gamma', 'A/B/F') 1231 1232 svntest.actions.run_and_verify_commit(wc_dir, 1233 expected_output, 1234 expected_status) 1235 1236 # Explicit update must not remove the 'deleted=true' entries 1237 svntest.actions.run_and_verify_svn(exp_noop_up_out(2), [], 1238 'update', gamma_path) 1239 svntest.actions.run_and_verify_svn(exp_noop_up_out(2), [], 1240 'update', F_path) 1241 1242 # Update to r1 to restore items, since the parent directory is already 1243 # at r1 this fails if the 'deleted=true' entries are missing (issue 2250) 1244 expected_output = svntest.wc.State(wc_dir, { 1245 'A/D/gamma' : Item(status='A '), 1246 'A/B/F' : Item(status='A '), 1247 }) 1248 1249 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 1250 1251 expected_disk = svntest.main.greek_state.copy() 1252 1253 svntest.actions.run_and_verify_update(wc_dir, 1254 expected_output, 1255 expected_disk, 1256 expected_status, 1257 [], False, 1258 '-r', '1', wc_dir) 1259 1260 1261 1262#---------------------------------------------------------------------- 1263 1264def new_dir_with_spaces(sbox): 1265 "receive new dir with spaces in its name" 1266 1267 sbox.build() 1268 wc_dir = sbox.wc_dir 1269 1270 # Create a new directory ("spacey dir") directly in repository 1271 svntest.actions.run_and_verify_svn(['Committing transaction...\n', 1272 'Committed revision 2.\n'], [], 1273 'mkdir', '-m', 'log msg', 1274 sbox.repo_url 1275 + '/A/spacey%20dir') 1276 1277 # Update, and make sure ra_neon doesn't choke on the space. 1278 expected_output = svntest.wc.State(wc_dir, { 1279 'A/spacey dir' : Item(status='A '), 1280 }) 1281 1282 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 1283 expected_status.add({ 1284 'A/spacey dir' : Item(status=' ', wc_rev=2), 1285 }) 1286 1287 expected_disk = svntest.main.greek_state.copy() 1288 expected_disk.add({ 1289 'A/spacey dir' : Item(), 1290 }) 1291 1292 svntest.actions.run_and_verify_update(wc_dir, 1293 expected_output, 1294 expected_disk, 1295 expected_status) 1296 1297#---------------------------------------------------------------------- 1298 1299def non_recursive_update(sbox): 1300 "non-recursive update" 1301 1302 sbox.build() 1303 wc_dir = sbox.wc_dir 1304 1305 # Commit a change to A/mu and A/D/G/rho 1306 mu_path = sbox.ospath('A/mu') 1307 rho_path = sbox.ospath('A/D/G/rho') 1308 1309 svntest.main.file_append(mu_path, "new") 1310 svntest.main.file_append(rho_path, "new") 1311 1312 expected_output = svntest.wc.State(wc_dir, { 1313 'A/mu' : Item(verb='Sending'), 1314 'A/D/G/rho' : Item(verb='Sending'), 1315 }) 1316 1317 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 1318 expected_status.tweak('A/mu', 'A/D/G/rho', wc_rev=2) 1319 1320 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 1321 expected_status) 1322 1323 # Update back to revision 1 1324 expected_output = svntest.wc.State(wc_dir, { 1325 'A/mu' : Item(status='U '), 1326 'A/D/G/rho' : Item(status='U '), 1327 }) 1328 1329 expected_disk = svntest.main.greek_state.copy() 1330 1331 expected_status.tweak('A/mu', 'A/D/G/rho', wc_rev=1) 1332 1333 svntest.actions.run_and_verify_update(wc_dir, expected_output, 1334 expected_disk, expected_status, 1335 [], False, 1336 '-r', '1', wc_dir) 1337 1338 # Non-recursive update of A should change A/mu but not A/D/G/rho 1339 A_path = sbox.ospath('A') 1340 1341 expected_output = svntest.wc.State(wc_dir, { 1342 'A/mu' : Item(status='U '), 1343 }) 1344 1345 expected_status.tweak('A', 'A/mu', wc_rev=2) 1346 1347 expected_disk.tweak('A/mu', contents="This is the file 'mu'.\nnew") 1348 1349 svntest.actions.run_and_verify_update(wc_dir, expected_output, 1350 expected_disk, expected_status, 1351 [], False, 1352 '-N', A_path) 1353 1354#---------------------------------------------------------------------- 1355 1356def checkout_empty_dir(sbox): 1357 "check out an empty dir" 1358 # See issue #1472 -- checked out empty dir should not be marked as 1359 # incomplete ("!" in status). 1360 sbox.build(create_wc = False) 1361 wc_dir = sbox.wc_dir 1362 1363 C_url = sbox.repo_url + '/A/C' 1364 1365 svntest.main.safe_rmtree(wc_dir) 1366 svntest.actions.run_and_verify_svn(None, [], 'checkout', C_url, wc_dir) 1367 1368 svntest.actions.run_and_verify_svn([], [], 'status', wc_dir) 1369 1370 1371#---------------------------------------------------------------------- 1372# Regression test for issue #919: "another ghudson bug". Basically, if 1373# we fore- or back-date an item until it no longer exists, we were 1374# completely removing the entry, rather than marking it 'deleted' 1375# (which we now do.) 1376 1377def update_to_deletion(sbox): 1378 "update target till it's gone, then get it back" 1379 1380 sbox.build() 1381 wc_dir = sbox.wc_dir 1382 1383 iota_path = sbox.ospath('iota') 1384 1385 # Update iota to rev 0, so it gets removed. 1386 expected_output = svntest.wc.State(wc_dir, { 1387 'iota' : Item(status='D '), 1388 }) 1389 1390 expected_disk = svntest.main.greek_state.copy() 1391 expected_disk.remove('iota') 1392 1393 svntest.actions.run_and_verify_update(wc_dir, 1394 expected_output, 1395 expected_disk, 1396 None, 1397 [], False, 1398 '-r', '0', iota_path) 1399 1400 # Update the wc root, so iota comes back. 1401 expected_output = svntest.wc.State(wc_dir, { 1402 'iota' : Item(status='A '), 1403 }) 1404 1405 expected_disk = svntest.main.greek_state.copy() 1406 1407 svntest.actions.run_and_verify_update(wc_dir, 1408 expected_output, 1409 expected_disk, 1410 None) 1411 1412 1413#---------------------------------------------------------------------- 1414 1415def update_deletion_inside_out(sbox): 1416 "update child before parent of a deleted tree" 1417 1418 sbox.build() 1419 wc_dir = sbox.wc_dir 1420 1421 parent_path = sbox.ospath('A/B') 1422 child_path = os.path.join(parent_path, 'E') # Could be a file, doesn't matter 1423 1424 # Delete the parent directory. 1425 svntest.actions.run_and_verify_svn(None, [], 1426 'rm', parent_path) 1427 svntest.actions.run_and_verify_svn(None, [], 1428 'ci', '-m', '', wc_dir) 1429 1430 # Update back to r1. 1431 svntest.actions.run_and_verify_svn(None, [], 1432 'update', '-r', '1', wc_dir) 1433 1434 # Update just the child to r2. 1435 svntest.actions.run_and_verify_svn(None, [], 1436 'update', '-r', '2', child_path) 1437 1438 # Now try a normal update. 1439 expected_output = svntest.wc.State(wc_dir, { 1440 'A/B' : Item(status='D '), 1441 }) 1442 1443 expected_disk = svntest.main.greek_state.copy() 1444 expected_disk.remove('A/B', 'A/B/lambda', 'A/B/F', 1445 'A/B/E', 'A/B/E/alpha', 'A/B/E/beta') 1446 1447 svntest.actions.run_and_verify_update(wc_dir, 1448 expected_output, 1449 expected_disk, 1450 None) 1451 1452 1453#---------------------------------------------------------------------- 1454# Regression test for issue #1793, whereby 'svn up dir' would delete 1455# dir if schedule-add. Yikes. 1456 1457def update_schedule_add_dir(sbox): 1458 "update a schedule-add directory" 1459 1460 sbox.build() 1461 wc_dir = sbox.wc_dir 1462 1463 # Delete directory A/D/G in the repository via immediate commit 1464 G_path = sbox.ospath('A/D/G') 1465 G_url = sbox.repo_url + '/A/D/G' 1466 svntest.actions.run_and_verify_svn(None, [], 1467 'rm', G_url, '-m', 'rev 2') 1468 1469 # Update the wc to HEAD (r2) 1470 expected_output = svntest.wc.State(wc_dir, { 1471 'A/D/G' : Item(status='D '), 1472 }) 1473 1474 expected_disk = svntest.main.greek_state.copy() 1475 expected_disk.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau') 1476 1477 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 1478 expected_status.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau') 1479 1480 svntest.actions.run_and_verify_update(wc_dir, 1481 expected_output, 1482 expected_disk, 1483 expected_status) 1484 1485 # Do a URL->wc copy, creating a new schedule-add A/D/G. 1486 # (Standard procedure when trying to resurrect the directory.) 1487 D_path = sbox.ospath('A/D') 1488 svntest.actions.run_and_verify_svn(None, [], 1489 'cp', G_url + '@1', D_path) 1490 1491 # status should now show the dir scheduled for addition-with-history 1492 expected_status.add({ 1493 'A/D/G' : Item(status='A ', copied='+', wc_rev='-'), 1494 'A/D/G/pi' : Item(status=' ', copied='+', wc_rev='-'), 1495 'A/D/G/rho' : Item(status=' ', copied='+', wc_rev='-'), 1496 'A/D/G/tau' : Item(status=' ', copied='+', wc_rev='-'), 1497 }) 1498 1499 svntest.actions.run_and_verify_status(wc_dir, expected_status) 1500 1501 # Now update with the schedule-add dir as the target. 1502 svntest.actions.run_and_verify_svn(None, [], 'up', G_path) 1503 1504 # The update should be a no-op, and the schedule-add directory 1505 # should still exist! 'svn status' shouldn't change at all. 1506 svntest.actions.run_and_verify_status(wc_dir, expected_status) 1507 1508 1509#---------------------------------------------------------------------- 1510# Test updating items that do not exist in the current WC rev, but do 1511# exist at some future revision. 1512 1513def update_to_future_add(sbox): 1514 "update target that was added in a future rev" 1515 1516 sbox.build() 1517 wc_dir = sbox.wc_dir 1518 1519 # Update the entire WC to rev 0 1520 # Create expected output tree for an update to rev 0 1521 expected_output = svntest.wc.State(wc_dir, { 1522 'iota' : Item(status='D '), 1523 'A' : Item(status='D '), 1524 }) 1525 1526 # Create expected disk tree for the update to rev 0 1527 expected_disk = svntest.wc.State(wc_dir, { }) 1528 1529 # Do the update and check the results. 1530 svntest.actions.run_and_verify_update(wc_dir, 1531 expected_output, 1532 expected_disk, 1533 None, 1534 [], False, 1535 '-r', '0', wc_dir) 1536 1537 # Update iota to the current HEAD. 1538 iota_path = sbox.ospath('iota') 1539 1540 expected_output = svntest.wc.State(wc_dir, { 1541 'iota' : Item(status='A '), 1542 }) 1543 1544 expected_disk = svntest.wc.State('', { 1545 'iota' : Item("This is the file 'iota'.\n") 1546 }) 1547 1548 svntest.actions.run_and_verify_update(wc_dir, 1549 expected_output, 1550 expected_disk, 1551 None, 1552 [], False, 1553 iota_path) 1554 1555 # Now try updating the directory into the future 1556 A_path = sbox.ospath('A') 1557 1558 expected_output = svntest.wc.State(wc_dir, { 1559 'A' : Item(status='A '), 1560 'A/mu' : Item(status='A '), 1561 'A/B' : Item(status='A '), 1562 'A/B/lambda' : Item(status='A '), 1563 'A/B/E' : Item(status='A '), 1564 'A/B/E/alpha' : Item(status='A '), 1565 'A/B/E/beta' : Item(status='A '), 1566 'A/B/F' : Item(status='A '), 1567 'A/C' : Item(status='A '), 1568 'A/D' : Item(status='A '), 1569 'A/D/gamma' : Item(status='A '), 1570 'A/D/G' : Item(status='A '), 1571 'A/D/G/pi' : Item(status='A '), 1572 'A/D/G/rho' : Item(status='A '), 1573 'A/D/G/tau' : Item(status='A '), 1574 'A/D/H' : Item(status='A '), 1575 'A/D/H/chi' : Item(status='A '), 1576 'A/D/H/psi' : Item(status='A '), 1577 'A/D/H/omega' : Item(status='A ') 1578 }) 1579 1580 expected_disk = svntest.main.greek_state.copy() 1581 1582 svntest.actions.run_and_verify_update(wc_dir, 1583 expected_output, 1584 expected_disk, 1585 None, 1586 [], False, 1587 A_path) 1588 1589#---------------------------------------------------------------------- 1590 1591def update_xml_unsafe_dir(sbox): 1592 "update dir with xml-unsafe name" 1593 1594 sbox.build() 1595 wc_dir = sbox.wc_dir 1596 1597 # Make a backup copy of the working copy 1598 wc_backup = sbox.add_wc_path('backup') 1599 svntest.actions.duplicate_dir(wc_dir, wc_backup) 1600 1601 # Make a couple of local mods to files 1602 test_path = sbox.ospath(' foo & bar') 1603 svntest.main.run_svn(None, 'mkdir', test_path) 1604 1605 # Created expected output tree for 'svn ci' 1606 expected_output = wc.State(wc_dir, { 1607 ' foo & bar' : Item(verb='Adding'), 1608 }) 1609 1610 # Create expected status tree; all local revisions should be at 1, 1611 # but 'foo & bar' should be at revision 2. 1612 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 1613 expected_status.add({ 1614 ' foo & bar' : Item(status=' ', wc_rev=2), 1615 }) 1616 1617 # Commit. 1618 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 1619 expected_status) 1620 1621 # chdir into the funky path, and update from there. 1622 os.chdir(test_path) 1623 1624 expected_output = wc.State('', { 1625 }) 1626 1627 expected_disk = wc.State('', { 1628 }) 1629 1630 expected_status = wc.State('', { 1631 '' : Item(status=' ', wc_rev=2), 1632 }) 1633 1634 svntest.actions.run_and_verify_update('', expected_output, expected_disk, 1635 expected_status) 1636 1637#---------------------------------------------------------------------- 1638# eol-style handling during update with conflicts, scenario 1: 1639# when update creates a conflict on a file, make sure the file and files 1640# r<left>, r<right> and .mine are in the eol-style defined for that file. 1641# 1642# This test for 'svn merge' can be found in merge_tests.py as 1643# merge_conflict_markers_matching_eol. 1644def conflict_markers_matching_eol(sbox): 1645 "conflict markers should match the file's eol style" 1646 1647 sbox.build() 1648 wc_dir = sbox.wc_dir 1649 filecount = 1 1650 1651 mu_path = sbox.ospath('A/mu') 1652 1653 if os.name == 'nt': 1654 native_nl = '\r\n' 1655 else: 1656 native_nl = '\n' 1657 crlf = '\r\n' 1658 1659 # Checkout a second working copy 1660 wc_backup = sbox.add_wc_path('backup') 1661 svntest.actions.run_and_verify_svn(None, [], 'checkout', 1662 sbox.repo_url, wc_backup) 1663 1664 # set starting revision 1665 cur_rev = 1 1666 1667 expected_disk = svntest.main.greek_state.copy() 1668 expected_status = svntest.actions.get_virginal_state(wc_dir, cur_rev) 1669 expected_backup_status = svntest.actions.get_virginal_state(wc_backup, 1670 cur_rev) 1671 1672 path_backup = os.path.join(wc_backup, 'A', 'mu') 1673 1674 # do the test for each eol-style 1675 for eol, eolchar in zip(['CRLF', 'CR', 'native', 'LF'], 1676 [crlf, '\015', native_nl, '\012']): 1677 # rewrite file mu and set the eol-style property. 1678 svntest.main.file_write(mu_path, "This is the file 'mu'."+ eolchar, 'wb') 1679 svntest.main.run_svn(None, 'propset', 'svn:eol-style', eol, mu_path) 1680 1681 expected_disk.add({ 1682 'A/mu' : Item("This is the file 'mu'." + eolchar) 1683 }) 1684 1685 expected_output = svntest.wc.State(wc_dir, { 1686 'A/mu' : Item(verb='Sending'), 1687 }) 1688 1689 expected_status.tweak(wc_rev = cur_rev) 1690 expected_status.add({ 1691 'A/mu' : Item(status=' ', wc_rev = cur_rev + 1), 1692 }) 1693 1694 # Commit the original change and note the 'base' revision number 1695 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 1696 expected_status) 1697 cur_rev = cur_rev + 1 1698 base_rev = cur_rev 1699 1700 svntest.main.run_svn(None, 'update', wc_backup) 1701 1702 # Make a local mod to mu 1703 svntest.main.file_append_binary(mu_path, 1704 'Original appended text for mu' + eolchar) 1705 1706 # Commit the original change and note the 'theirs' revision number 1707 svntest.main.run_svn(None, 'commit', '-m', 'test log', wc_dir) 1708 cur_rev = cur_rev + 1 1709 theirs_rev = cur_rev 1710 1711 # Make a local mod to mu, will conflict with the previous change 1712 svntest.main.file_append_binary(path_backup, 1713 'Conflicting appended text for mu' 1714 + eolchar) 1715 1716 # Create expected output tree for an update of the wc_backup. 1717 expected_backup_output = svntest.wc.State(wc_backup, { 1718 'A/mu' : Item(status='C '), 1719 }) 1720 1721 # Create expected disk tree for the update. 1722 expected_backup_disk = expected_disk.copy() 1723 1724 # verify content of resulting conflicted file 1725 expected_backup_disk.add({ 1726 'A/mu' : Item(contents= "This is the file 'mu'." + eolchar + 1727 "<<<<<<< .mine" + eolchar + 1728 "Conflicting appended text for mu" + eolchar + 1729 "||||||| .r" + str(cur_rev - 1) + eolchar + 1730 "=======" + eolchar + 1731 "Original appended text for mu" + eolchar + 1732 ">>>>>>> .r" + str(cur_rev) + eolchar), 1733 }) 1734 # verify content of base(left) file 1735 expected_backup_disk.add({ 1736 'A/mu.r' + str(base_rev ) : Item(contents= "This is the file 'mu'." + 1737 eolchar) 1738 }) 1739 # verify content of theirs(right) file 1740 expected_backup_disk.add({ 1741 'A/mu.r' + str(theirs_rev ) : Item(contents= "This is the file 'mu'." + 1742 eolchar + 1743 "Original appended text for mu" + eolchar) 1744 }) 1745 # verify content of mine file 1746 expected_backup_disk.add({ 1747 'A/mu.mine' : Item(contents= "This is the file 'mu'." + 1748 eolchar + 1749 "Conflicting appended text for mu" + eolchar) 1750 }) 1751 1752 # Create expected status tree for the update. 1753 expected_backup_status.add({ 1754 'A/mu' : Item(status=' ', wc_rev=cur_rev), 1755 }) 1756 expected_backup_status.tweak('A/mu', status='C ') 1757 expected_backup_status.tweak(wc_rev = cur_rev) 1758 1759 # Do the update and check the results in three ways. 1760 svntest.actions.run_and_verify_update2(wc_backup, 1761 expected_backup_output, 1762 expected_backup_disk, 1763 expected_backup_status, 1764 keep_eol_style=True) 1765 1766 # cleanup for next run 1767 svntest.main.run_svn(None, 'revert', '-R', wc_backup) 1768 svntest.main.run_svn(None, 'update', wc_dir) 1769 1770# eol-style handling during update, scenario 2: 1771# if part of that update is a propchange (add, change, delete) of 1772# svn:eol-style, make sure the correct eol-style is applied before 1773# calculating the merge (and conflicts if any) 1774# 1775# This test for 'svn merge' can be found in merge_tests.py as 1776# merge_eolstyle_handling. 1777def update_eolstyle_handling(sbox): 1778 "handle eol-style propchange during update" 1779 1780 sbox.build() 1781 wc_dir = sbox.wc_dir 1782 1783 mu_path = sbox.ospath('A/mu') 1784 1785 crlf = '\r\n' 1786 1787 # Checkout a second working copy 1788 wc_backup = sbox.add_wc_path('backup') 1789 svntest.actions.run_and_verify_svn(None, [], 'checkout', 1790 sbox.repo_url, wc_backup) 1791 path_backup = os.path.join(wc_backup, 'A', 'mu') 1792 1793 # Test 1: add the eol-style property and commit, change mu in the second 1794 # working copy and update; there should be no conflict! 1795 svntest.main.run_svn(None, 'propset', 'svn:eol-style', "CRLF", mu_path) 1796 svntest.main.run_svn(None, 1797 'commit', '-m', 'set eol-style property', wc_dir) 1798 1799 svntest.main.file_append_binary(path_backup, 'Added new line of text.\012') 1800 1801 expected_backup_disk = svntest.main.greek_state.copy() 1802 expected_backup_disk.tweak( 1803 'A/mu', contents= "This is the file 'mu'." + crlf + 1804 "Added new line of text." + crlf) 1805 1806 expected_backup_output = svntest.wc.State(wc_backup, { 1807 'A/mu' : Item(status='GU'), 1808 }) 1809 1810 expected_backup_status = svntest.actions.get_virginal_state(wc_backup, 2) 1811 expected_backup_status.tweak('A/mu', status='M ') 1812 1813 svntest.actions.run_and_verify_update2(wc_backup, 1814 expected_backup_output, 1815 expected_backup_disk, 1816 expected_backup_status, 1817 keep_eol_style=True) 1818 1819 # Test 2: now change the eol-style property to another value and commit, 1820 # update the still changed mu in the second working copy; there should be 1821 # no conflict! 1822 svntest.main.run_svn(None, 'propset', 'svn:eol-style', "CR", mu_path) 1823 svntest.main.run_svn(None, 1824 'commit', '-m', 'set eol-style property', wc_dir) 1825 1826 expected_backup_disk = svntest.main.greek_state.copy() 1827 expected_backup_disk.add({ 1828 'A/mu' : Item(contents= "This is the file 'mu'.\015" + 1829 "Added new line of text.\015") 1830 }) 1831 1832 expected_backup_output = svntest.wc.State(wc_backup, { 1833 'A/mu' : Item(status='GU'), 1834 }) 1835 1836 expected_backup_status = svntest.actions.get_virginal_state(wc_backup, 3) 1837 expected_backup_status.tweak('A/mu', status='M ') 1838 1839 svntest.actions.run_and_verify_update2(wc_backup, 1840 expected_backup_output, 1841 expected_backup_disk, 1842 expected_backup_status, 1843 keep_eol_style=True) 1844 1845 # Test 3: now delete the eol-style property and commit, update the still 1846 # changed mu in the second working copy; there should be no conflict! 1847 # EOL of mu should be unchanged (=CR). 1848 svntest.main.run_svn(None, 'propdel', 'svn:eol-style', mu_path) 1849 svntest.main.run_svn(None, 1850 'commit', '-m', 'del eol-style property', wc_dir) 1851 1852 expected_backup_disk = svntest.main.greek_state.copy() 1853 expected_backup_disk.add({ 1854 'A/mu' : Item(contents= "This is the file 'mu'.\015" + 1855 "Added new line of text.\015") 1856 }) 1857 1858 expected_backup_output = svntest.wc.State(wc_backup, { 1859 'A/mu' : Item(status=' U'), 1860 }) 1861 1862 expected_backup_status = svntest.actions.get_virginal_state(wc_backup, 4) 1863 expected_backup_status.tweak('A/mu', status='M ') 1864 svntest.actions.run_and_verify_update2(wc_backup, 1865 expected_backup_output, 1866 expected_backup_disk, 1867 expected_backup_status, 1868 keep_eol_style=True) 1869 1870# Bug in which "update" put a bogus revision number on a schedule-add file, 1871# causing the wrong version of it to be committed. 1872def update_copy_of_old_rev(sbox): 1873 "update schedule-add copy of old rev" 1874 1875 sbox.build() 1876 wc_dir = sbox.wc_dir 1877 1878 dir = sbox.ospath('A') 1879 dir2 = sbox.ospath('A2') 1880 file = os.path.join(dir, 'mu') 1881 file2 = os.path.join(dir2, 'mu') 1882 url = sbox.repo_url + '/A/mu' 1883 url2 = sbox.repo_url + '/A2/mu' 1884 1885 # Remember the original text of the file 1886 exit_code, text_r1, err = svntest.actions.run_and_verify_svn(None, [], 1887 'cat', '-r1', 1888 url) 1889 1890 # Commit a different version of the file 1891 svntest.main.file_write(file, "Second revision of 'mu'\n") 1892 svntest.actions.run_and_verify_svn(None, [], 1893 'ci', '-m', '', wc_dir) 1894 1895 # Copy an old revision of its directory into a new path in the WC 1896 svntest.actions.run_and_verify_svn(None, [], 1897 'cp', '-r1', dir, dir2) 1898 1899 # Update. (Should do nothing, but added a bogus "revision" in "entries".) 1900 svntest.actions.run_and_verify_svn(None, [], 1901 'up', wc_dir) 1902 1903 # Commit, and check that it says it's committing the right thing 1904 exp_out = ['Adding ' + dir2 + '\n', 1905 'Committing transaction...\n', 1906 'Committed revision 3.\n'] 1907 svntest.actions.run_and_verify_svn(exp_out, [], 1908 'ci', '-m', '', wc_dir) 1909 1910 # Verify the committed file's content 1911 svntest.actions.run_and_verify_svn(text_r1, [], 1912 'cat', url2) 1913 1914#---------------------------------------------------------------------- 1915def forced_update(sbox): 1916 "forced update tolerates obstructions to adds" 1917 1918 sbox.build() 1919 wc_dir = sbox.wc_dir 1920 1921 # Make a backup copy of the working copy 1922 wc_backup = sbox.add_wc_path('backup') 1923 svntest.actions.duplicate_dir(wc_dir, wc_backup) 1924 1925 # Make a couple of local mods to files 1926 mu_path = sbox.ospath('A/mu') 1927 rho_path = sbox.ospath('A/D/G/rho') 1928 svntest.main.file_append(mu_path, 'appended mu text') 1929 svntest.main.file_append(rho_path, 'new appended text for rho') 1930 1931 # Add some files 1932 nu_path = sbox.ospath('A/B/F/nu') 1933 svntest.main.file_append(nu_path, "This is the file 'nu'\n") 1934 svntest.main.run_svn(None, 'add', nu_path) 1935 kappa_path = sbox.ospath('kappa') 1936 svntest.main.file_append(kappa_path, "This is the file 'kappa'\n") 1937 svntest.main.run_svn(None, 'add', kappa_path) 1938 1939 # Add a dir with two files 1940 I_path = sbox.ospath('A/C/I') 1941 os.mkdir(I_path) 1942 svntest.main.run_svn(None, 'add', I_path) 1943 upsilon_path = os.path.join(I_path, 'upsilon') 1944 svntest.main.file_append(upsilon_path, "This is the file 'upsilon'\n") 1945 svntest.main.run_svn(None, 'add', upsilon_path) 1946 zeta_path = os.path.join(I_path, 'zeta') 1947 svntest.main.file_append(zeta_path, "This is the file 'zeta'\n") 1948 svntest.main.run_svn(None, 'add', zeta_path) 1949 1950 # Created expected output tree for 'svn ci' 1951 expected_output = wc.State(wc_dir, { 1952 'A/mu' : Item(verb='Sending'), 1953 'A/D/G/rho' : Item(verb='Sending'), 1954 'A/B/F/nu' : Item(verb='Adding'), 1955 'kappa' : Item(verb='Adding'), 1956 'A/C/I' : Item(verb='Adding'), 1957 'A/C/I/upsilon' : Item(verb='Adding'), 1958 'A/C/I/zeta' : Item(verb='Adding'), 1959 }) 1960 1961 # Create expected status tree. 1962 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 1963 expected_status.add({ 1964 'A/B/F/nu' : Item(status=' ', wc_rev=2), 1965 'kappa' : Item(status=' ', wc_rev=2), 1966 'A/C/I' : Item(status=' ', wc_rev=2), 1967 'A/C/I/upsilon' : Item(status=' ', wc_rev=2), 1968 'A/C/I/zeta' : Item(status=' ', wc_rev=2), 1969 }) 1970 expected_status.tweak('A/mu', 'A/D/G/rho', wc_rev=2) 1971 1972 # Commit. 1973 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 1974 expected_status) 1975 1976 # Make a local mod to mu that will merge cleanly. 1977 backup_mu_path = os.path.join(wc_backup, 'A', 'mu') 1978 svntest.main.file_append(backup_mu_path, 'appended mu text') 1979 1980 # Create unversioned files and dir that will obstruct A/B/F/nu, kappa, 1981 # A/C/I, and A/C/I/upsilon coming from repos during update. 1982 # The obstructing nu has the same contents as the repos, while kappa and 1983 # upsilon differ, which means the latter two should show as modified after 1984 # the forced update. 1985 nu_path = os.path.join(wc_backup, 'A', 'B', 'F', 'nu') 1986 svntest.main.file_append(nu_path, "This is the file 'nu'\n") 1987 kappa_path = os.path.join(wc_backup, 'kappa') 1988 svntest.main.file_append(kappa_path, 1989 "This is the OBSTRUCTING file 'kappa'\n") 1990 I_path = os.path.join(wc_backup, 'A', 'C', 'I') 1991 os.mkdir(I_path) 1992 upsilon_path = os.path.join(I_path, 'upsilon') 1993 svntest.main.file_append(upsilon_path, 1994 "This is the OBSTRUCTING file 'upsilon'\n") 1995 1996 # Create expected output tree for an update of the wc_backup. 1997 # mu and rho are run of the mill update operations; merge and update 1998 # respectively. 1999 # kappa, nu, I, and upsilon all 'E'xisted as unversioned items in the WC. 2000 # While the dir I does exist, zeta does not so it's just an add. 2001 expected_output = wc.State(wc_backup, { 2002 'A/mu' : Item(status='G '), 2003 'A/D/G/rho' : Item(status='U '), 2004 'kappa' : Item(status='E '), 2005 'A/B/F/nu' : Item(status='E '), 2006 'A/C/I' : Item(status='E '), 2007 'A/C/I/upsilon' : Item(status='E '), 2008 'A/C/I/zeta' : Item(status='A '), 2009 }) 2010 2011 # Create expected output tree for an update of the wc_backup. 2012 # 2013 # - mu and rho are run of the mill update operations; merge and update 2014 # respectively. 2015 # 2016 # - kappa, nu, I, and upsilon all 'E'xisted as unversioned items in the WC. 2017 # 2018 # - While the dir I does exist, I/zeta does not so it's just an add. 2019 expected_disk = svntest.main.greek_state.copy() 2020 expected_disk.add({ 2021 'A/B/F/nu' : Item("This is the file 'nu'\n"), 2022 'kappa' : Item("This is the OBSTRUCTING file 'kappa'\n"), 2023 'A/C/I' : Item(), 2024 'A/C/I/upsilon' : Item("This is the OBSTRUCTING file 'upsilon'\n"), 2025 'A/C/I/zeta' : Item("This is the file 'zeta'\n"), 2026 }) 2027 expected_disk.tweak('A/mu', 2028 contents=expected_disk.desc['A/mu'].contents 2029 + 'appended mu text') 2030 expected_disk.tweak('A/D/G/rho', 2031 contents=expected_disk.desc['A/D/G/rho'].contents 2032 + 'new appended text for rho') 2033 2034 # Create expected status tree for the update. Since the obstructing 2035 # kappa and upsilon differ from the repos, they should show as modified. 2036 expected_status = svntest.actions.get_virginal_state(wc_backup, 2) 2037 expected_status.add({ 2038 'A/B/F/nu' : Item(status=' ', wc_rev=2), 2039 'A/C/I' : Item(status=' ', wc_rev=2), 2040 'A/C/I/zeta' : Item(status=' ', wc_rev=2), 2041 'kappa' : Item(status='M ', wc_rev=2), 2042 'A/C/I/upsilon' : Item(status='M ', wc_rev=2), 2043 }) 2044 2045 # Perform forced update and check the results in three ways. 2046 svntest.actions.run_and_verify_update(wc_backup, 2047 expected_output, 2048 expected_disk, 2049 expected_status, 2050 [], False, 2051 wc_backup, '--force') 2052 2053#---------------------------------------------------------------------- 2054def forced_update_failures(sbox): 2055 "forced up fails with some types of obstructions" 2056 2057 sbox.build() 2058 wc_dir = sbox.wc_dir 2059 2060 # Make a backup copy of the working copy 2061 wc_backup = sbox.add_wc_path('backup') 2062 svntest.actions.duplicate_dir(wc_dir, wc_backup) 2063 2064 # Add a file 2065 nu_path = sbox.ospath('A/B/F/nu') 2066 svntest.main.file_append(nu_path, "This is the file 'nu'\n") 2067 svntest.main.run_svn(None, 'add', nu_path) 2068 2069 # Add a dir 2070 I_path = sbox.ospath('A/C/I') 2071 os.mkdir(I_path) 2072 svntest.main.run_svn(None, 'add', I_path) 2073 2074 # Created expected output tree for 'svn ci' 2075 expected_output = wc.State(wc_dir, { 2076 'A/B/F/nu' : Item(verb='Adding'), 2077 'A/C/I' : Item(verb='Adding'), 2078 }) 2079 2080 # Create expected status tree. 2081 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 2082 expected_status.add({ 2083 'A/B/F/nu' : Item(status=' ', wc_rev=2), 2084 'A/C/I' : Item(status=' ', wc_rev=2), 2085 }) 2086 2087 # Commit. 2088 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 2089 expected_status) 2090 2091 # Create an unversioned dir A/B/F/nu that will obstruct the file of the 2092 # same name coming from the repository. Create an unversioned file A/C/I 2093 # that will obstruct the dir of the same name. 2094 nu_path = os.path.join(wc_backup, 'A', 'B', 'F', 'nu') 2095 os.mkdir(nu_path) 2096 I_path = os.path.join(wc_backup, 'A', 'C', 'I') 2097 svntest.main.file_append(I_path, 2098 "This is the file 'I'...shouldn't I be a dir?\n") 2099 2100 # A forced update that tries to add a file when an unversioned directory 2101 # of the same name already exists should fail. 2102 #svntest.factory.make(sbox, """svn up --force $WC_DIR.backup/A/B/F""") 2103 #exit(0) 2104 backup_A_B_F = os.path.join(wc_backup, 'A', 'B', 'F') 2105 2106 # svn up --force $WC_DIR.backup/A/B/F 2107 expected_output = svntest.wc.State(wc_backup, { 2108 'A/B/F/nu' : Item(status=' ', treeconflict='C'), 2109 }) 2110 2111 expected_disk = svntest.main.greek_state.copy() 2112 expected_disk.add({ 2113 'A/B/F/nu' : Item(), 2114 'A/C/I' : 2115 Item(contents="This is the file 'I'...shouldn't I be a dir?\n"), 2116 }) 2117 2118 expected_status = actions.get_virginal_state(wc_backup, 1) 2119 expected_status.add({ 2120 'A/B/F/nu' : Item(status='D ', treeconflict='C', wc_rev='2'), 2121 }) 2122 expected_status.tweak('A/B/F', wc_rev='2') 2123 2124 actions.run_and_verify_update(wc_backup, expected_output, 2125 expected_disk, expected_status, 2126 [], False, 2127 '--force', backup_A_B_F) 2128 2129 2130 # A forced update that tries to add a directory when an unversioned file 2131 # of the same name already exists should fail. 2132 # svntest.factory.make(sbox, """ 2133 # svn up --force wc_dir_backup/A/C 2134 # rm -rf wc_dir_backup/A/C/I wc_dir_backup/A/B/F/nu 2135 # svn up wc_dir_backup 2136 # svn up -r1 wc_dir_backup/A/C 2137 # svn co url/A/C/I wc_dir_backup/A/C/I 2138 # svn up --force wc_dir_backup/A/C 2139 # """) 2140 # exit(0) 2141 url = sbox.repo_url 2142 wc_dir_backup = sbox.wc_dir + '.backup' 2143 2144 backup_A_B_F_nu = os.path.join(wc_dir_backup, 'A', 'B', 'F', 'nu') 2145 backup_A_C = os.path.join(wc_dir_backup, 'A', 'C') 2146 backup_A_C_I = os.path.join(wc_dir_backup, 'A', 'C', 'I') 2147 url_A_C_I = url + '/A/C/I' 2148 2149 # svn up --force wc_dir_backup/A/C 2150 expected_output = svntest.wc.State(wc_dir_backup, { 2151 'A/C/I' : Item(status=' ', treeconflict='C'), 2152 }) 2153 2154 expected_disk = svntest.main.greek_state.copy() 2155 expected_disk.add({ 2156 'A/B/F/nu' : Item(), 2157 'A/C/I' : 2158 Item(contents="This is the file 'I'...shouldn't I be a dir?\n"), 2159 }) 2160 2161 expected_status = actions.get_virginal_state(wc_dir_backup, 1) 2162 expected_status.add({ 2163 'A/C/I' : Item(status='D ', treeconflict='C', wc_rev=2), 2164 'A/B/F/nu' : Item(status='D ', treeconflict='C', wc_rev=2), 2165 }) 2166 expected_status.tweak('A/C', 'A/B/F', wc_rev='2') 2167 2168 actions.run_and_verify_update(wc_dir_backup, expected_output, 2169 expected_disk, expected_status, 2170 [], False, 2171 '--force', backup_A_C) 2172 2173 # rm -rf wc_dir_backup/A/C/I wc_dir_backup/A/B/F/nu 2174 os.remove(backup_A_C_I) 2175 svntest.main.safe_rmtree(backup_A_B_F_nu) 2176 2177 svntest.main.run_svn(None, 'revert', backup_A_C_I, backup_A_B_F_nu) 2178 2179 # svn up wc_dir_backup 2180 expected_output = svntest.wc.State(wc_dir_backup, { 2181 }) 2182 2183 expected_disk.tweak('A/B/F/nu', contents="This is the file 'nu'\n") 2184 expected_disk.tweak('A/C/I', contents=None) 2185 2186 expected_status.tweak(wc_rev='2', status=' ') 2187 expected_status.tweak('A/C/I', 'A/B/F/nu', treeconflict=None) 2188 2189 actions.run_and_verify_update(wc_dir_backup, expected_output, 2190 expected_disk, expected_status) 2191 2192 # svn up -r1 wc_dir_backup/A/C 2193 expected_output = svntest.wc.State(wc_dir_backup, { 2194 'A/C/I' : Item(status='D '), 2195 }) 2196 2197 expected_disk.remove('A/C/I') 2198 2199 expected_status.remove('A/C/I') 2200 expected_status.tweak('A/C', wc_rev='1') 2201 2202 actions.run_and_verify_update(wc_dir_backup, expected_output, 2203 expected_disk, expected_status, 2204 [], False, 2205 '-r1', backup_A_C) 2206 2207 # svn co url/A/C/I wc_dir_backup/A/C/I 2208 expected_output = svntest.wc.State(wc_dir_backup, {}) 2209 2210 expected_disk = svntest.wc.State(wc_dir, {}) 2211 2212 actions.run_and_verify_checkout(url_A_C_I, backup_A_C_I, 2213 expected_output, expected_disk) 2214 2215 # svn up --force wc_dir_backup/A/C 2216 expected_output = svntest.wc.State(wc_dir_backup, { 2217 'A/C/I' : Item(verb='Skipped'), 2218 }) 2219 2220 actions.run_and_verify_update(wc_dir_backup, expected_output, None, None, 2221 [], False, 2222 '--force', backup_A_C) 2223 2224 2225#---------------------------------------------------------------------- 2226# Test for issue #2556. The tests maps a virtual drive to a working copy 2227# and tries some basic update, commit and status actions on the virtual 2228# drive. 2229@SkipUnless(svntest.main.is_os_windows) 2230def update_wc_on_windows_drive(sbox): 2231 "update wc on the root of a Windows (virtual) drive" 2232 2233 def find_the_next_available_drive_letter(): 2234 "find the first available drive" 2235 2236 # get the list of used drive letters, use some Windows specific function. 2237 try: 2238 import win32api 2239 2240 drives=win32api.GetLogicalDriveStrings() 2241 drives=drives.split('\000') 2242 2243 for d in range(ord('G'), ord('Z')+1): 2244 drive = chr(d) 2245 if not drive + ':\\' in drives: 2246 return drive 2247 except ImportError: 2248 # In ActiveState python x64 win32api is not available 2249 for d in range(ord('G'), ord('Z')+1): 2250 drive = chr(d) 2251 if not os.path.isdir(drive + ':\\'): 2252 return drive 2253 2254 return None 2255 2256 # just create an empty folder, we'll checkout later. 2257 sbox.build(create_wc = False) 2258 svntest.main.safe_rmtree(sbox.wc_dir) 2259 os.mkdir(sbox.wc_dir) 2260 2261 # create a virtual drive to the working copy folder 2262 drive = find_the_next_available_drive_letter() 2263 if drive is None: 2264 raise svntest.Skip('No drive letter available') 2265 2266 subprocess.call(['subst', drive +':', sbox.wc_dir]) 2267 wc_dir = drive + ':/' 2268 was_cwd = os.getcwd() 2269 2270 try: 2271 svntest.actions.run_and_verify_svn(None, [], 2272 'checkout', 2273 sbox.repo_url, wc_dir) 2274 2275 # Make some local modifications 2276 mu_path = os.path.join(wc_dir, 'A', 'mu').replace(os.sep, '/') 2277 svntest.main.file_append(mu_path, '\nAppended text for mu') 2278 zeta_path = os.path.join(wc_dir, 'zeta').replace(os.sep, '/') 2279 svntest.main.file_append(zeta_path, "This is the file 'zeta'\n") 2280 svntest.main.run_svn(None, 'add', zeta_path) 2281 2282 # Commit. 2283 expected_output = svntest.wc.State(wc_dir, { 2284 'A/mu' : Item(verb='Sending'), 2285 'zeta' : Item(verb='Adding'), 2286 }) 2287 2288 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 2289 expected_status.tweak('A/mu', wc_rev=2) 2290 expected_status.add({ 2291 'zeta' : Item(status=' ', wc_rev=2), 2292 }) 2293 2294 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 2295 expected_status, [], 2296 wc_dir, zeta_path) 2297 2298 # Non recursive commit 2299 dir1_path = os.path.join(wc_dir, 'dir1').replace(os.sep, '/') 2300 os.mkdir(dir1_path) 2301 svntest.main.run_svn(None, 'add', '-N', dir1_path) 2302 file1_path = os.path.join(dir1_path, 'file1') 2303 svntest.main.file_append(file1_path, "This is the file 'file1'\n") 2304 svntest.main.run_svn(None, 'add', '-N', file1_path) 2305 2306 expected_output = svntest.wc.State(wc_dir, { 2307 'dir1' : Item(verb='Adding'), 2308 'dir1/file1' : Item(verb='Adding'), 2309 }) 2310 2311 expected_status.add({ 2312 'dir1' : Item(status=' ', wc_rev=3), 2313 'dir1/file1' : Item(status=' ', wc_rev=3), 2314 }) 2315 2316 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 2317 expected_status, [], 2318 '-N', 2319 wc_dir, 2320 dir1_path, file1_path) 2321 2322 # revert to previous revision to test update 2323 os.chdir(wc_dir) 2324 2325 expected_disk = svntest.main.greek_state.copy() 2326 2327 expected_output = svntest.wc.State('', { 2328 'A/mu' : Item(status='U '), 2329 'zeta' : Item(status='D '), 2330 'dir1' : Item(status='D '), 2331 }) 2332 2333 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 2334 2335 svntest.actions.run_and_verify_update(wc_dir, 2336 expected_output, 2337 expected_disk, 2338 expected_status, 2339 [], False, 2340 '-r', '1', wc_dir) 2341 2342 os.chdir(was_cwd) 2343 2344 # update to the latest version, but use the relative path 'X:' 2345 wc_dir = drive + ":" 2346 2347 expected_output = svntest.wc.State(wc_dir, { 2348 'A/mu' : Item(status='U '), 2349 'zeta' : Item(status='A '), 2350 'dir1' : Item(status='A '), 2351 'dir1/file1' : Item(status='A '), 2352 }) 2353 2354 expected_status = svntest.actions.get_virginal_state(wc_dir, 3) 2355 expected_status.add({ 2356 'dir1' : Item(status=' ', wc_rev=3), 2357 'dir1/file1' : Item(status=' ', wc_rev=3), 2358 'zeta' : Item(status=' ', wc_rev=3), 2359 }) 2360 2361 expected_disk.add({ 2362 'zeta' : Item("This is the file 'zeta'\n"), 2363 'dir1/file1': Item("This is the file 'file1'\n"), 2364 }) 2365 expected_disk.tweak('A/mu', contents = expected_disk.desc['A/mu'].contents 2366 + '\nAppended text for mu') 2367 2368 # Create expected status with 'H:iota' style paths 2369 expected_status_relative = svntest.wc.State('', {}) 2370 expected_status_relative.add_state(wc_dir, expected_status, strict=True) 2371 2372 svntest.actions.run_and_verify_update(wc_dir, 2373 expected_output, 2374 expected_disk, 2375 expected_status_relative) 2376 2377 finally: 2378 os.chdir(was_cwd) 2379 # cleanup the virtual drive 2380 subprocess.call(['subst', '/D', drive +':']) 2381 2382# Issue #2618: "'Checksum mismatch' error when receiving 2383# update for replaced-with-history file". 2384def update_wc_with_replaced_file(sbox): 2385 "update wc containing a replaced-with-history file" 2386 2387 sbox.build() 2388 wc_dir = sbox.wc_dir 2389 2390 # Make a backup copy of the working copy. 2391 wc_backup = sbox.add_wc_path('backup') 2392 svntest.actions.duplicate_dir(wc_dir, wc_backup) 2393 2394 # we need a change in the repository 2395 iota_path = sbox.ospath('iota') 2396 mu_path = sbox.ospath('A/mu') 2397 iota_bu_path = os.path.join(wc_backup, 'iota') 2398 svntest.main.file_append(iota_bu_path, "New line in 'iota'\n") 2399 svntest.main.run_svn(None, 2400 'ci', wc_backup, '-m', 'changed file') 2401 2402 # First, a replacement without history. 2403 svntest.main.run_svn(None, 'rm', iota_path) 2404 svntest.main.file_append(iota_path, "") 2405 svntest.main.run_svn(None, 'add', iota_path) 2406 2407 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 2408 expected_status.tweak('iota', status='R ', wc_rev='1') 2409 2410 svntest.actions.run_and_verify_status(wc_dir, expected_status) 2411 2412 # Now update the wc. The local replacement is a tree conflict with 2413 # the incoming edit on that deleted item. 2414 expected_output = svntest.wc.State(wc_dir, { 2415 'iota' : Item(status=' ', treeconflict='C'), 2416 }) 2417 2418 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 2419 expected_status.add({ 2420 'iota' : Item(status='R ', wc_rev='2', treeconflict='C'), 2421 }) 2422 2423 expected_disk = svntest.main.greek_state.copy() 2424 expected_disk.tweak('iota', contents="") 2425 2426 svntest.actions.run_and_verify_update(wc_dir, 2427 expected_output, 2428 expected_disk, 2429 expected_status) 2430 2431 # Make us a working copy with a 'replace-with-history' file. 2432 svntest.main.run_svn(None, 'revert', iota_path) 2433 2434 expected_output = svntest.wc.State(wc_dir, { 2435 'iota' : Item(status='U '), 2436 }) 2437 2438 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 2439 2440 expected_disk = svntest.main.greek_state.copy() 2441 2442 svntest.actions.run_and_verify_update(wc_dir, 2443 expected_output, 2444 expected_disk, 2445 expected_status, 2446 [], False, 2447 wc_dir, '-r1') 2448 2449 svntest.main.run_svn(None, 'rm', iota_path) 2450 svntest.main.run_svn(None, 'cp', mu_path, iota_path) 2451 2452 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 2453 expected_status.tweak('iota', status='R ', copied='+', wc_rev='-') 2454 2455 svntest.actions.run_and_verify_status(wc_dir, expected_status) 2456 2457 # Now update the wc. The local replacement is a tree conflict with 2458 # the incoming edit on that deleted item. 2459 expected_output = svntest.wc.State(wc_dir, { 2460 'iota' : Item(status=' ', treeconflict='C'), 2461 }) 2462 2463 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 2464 expected_status.add({ 2465 'iota' : Item(status='R ', wc_rev='-', treeconflict='C', copied='+'), 2466 }) 2467 2468 expected_disk = svntest.main.greek_state.copy() 2469 expected_disk.tweak('iota', contents="This is the file 'mu'.\n") 2470 2471 svntest.actions.run_and_verify_update(wc_dir, 2472 expected_output, 2473 expected_disk, 2474 expected_status) 2475 2476#---------------------------------------------------------------------- 2477def update_with_obstructing_additions(sbox): 2478 "update handles obstructing paths scheduled for add" 2479 2480 sbox.build() 2481 wc_dir = sbox.wc_dir 2482 2483 # Make a backup copy of the working copy 2484 wc_backup = sbox.add_wc_path('backup') 2485 svntest.actions.duplicate_dir(wc_dir, wc_backup) 2486 2487 # Add files and dirs to the repos via the first WC. Each of these 2488 # will be added to the backup WC via an update: 2489 # 2490 # A/B/upsilon: Identical to the file scheduled for addition in 2491 # the backup WC. 2492 # 2493 # A/C/nu: A "normal" add, won't exist in the backup WC. 2494 # 2495 # A/D/kappa: Textual and property conflict with the file scheduled 2496 # for addition in the backup WC. 2497 # 2498 # A/D/epsilon: Textual conflict with the file scheduled for addition. 2499 # 2500 # A/D/zeta: Prop conflict with the file scheduled for addition. 2501 # 2502 # Three new dirs that will also be scheduled for addition: 2503 # A/D/H/I: No props on either WC or REPOS. 2504 # A/D/H/I/J: Prop conflict with the scheduled add. 2505 # A/D/H/I/K: Same (mergeable) prop on WC and REPOS. 2506 # 2507 # A/D/H/I/K/xi: Identical to the file scheduled for addition in 2508 # the backup WC. No props. 2509 # 2510 # A/D/H/I/L: A "normal" dir add, won't exist in the backup WC. 2511 # 2512 # A/D/H/I/J/eta: Conflicts with the file scheduled for addition in 2513 # the backup WC. No props. 2514 upsilon_path = sbox.ospath('A/B/upsilon') 2515 svntest.main.file_append(upsilon_path, "This is the file 'upsilon'\n") 2516 nu_path = sbox.ospath('A/C/nu') 2517 svntest.main.file_append(nu_path, "This is the file 'nu'\n") 2518 kappa_path = sbox.ospath('A/D/kappa') 2519 svntest.main.file_append(kappa_path, "This is REPOS file 'kappa'\n") 2520 epsilon_path = sbox.ospath('A/D/epsilon') 2521 svntest.main.file_append(epsilon_path, "This is REPOS file 'epsilon'\n") 2522 zeta_path = sbox.ospath('A/D/zeta') 2523 svntest.main.file_append(zeta_path, "This is the file 'zeta'\n") 2524 I_path = sbox.ospath('A/D/H/I') 2525 os.mkdir(I_path) 2526 J_path = os.path.join(I_path, 'J') 2527 os.mkdir(J_path) 2528 K_path = os.path.join(I_path, 'K') 2529 os.mkdir(K_path) 2530 L_path = os.path.join(I_path, 'L') 2531 os.mkdir(L_path) 2532 xi_path = os.path.join(K_path, 'xi') 2533 svntest.main.file_append(xi_path, "This is the file 'xi'\n") 2534 eta_path = os.path.join(J_path, 'eta') 2535 svntest.main.file_append(eta_path, "This is REPOS file 'eta'\n") 2536 2537 svntest.main.run_svn(None, 'add', upsilon_path, nu_path, 2538 kappa_path, epsilon_path, zeta_path, I_path) 2539 2540 # Set props that will conflict with scheduled adds. 2541 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-REPOS', 2542 kappa_path) 2543 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-REPOS', 2544 zeta_path) 2545 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-REPOS', 2546 J_path) 2547 2548 # Set prop that will match with scheduled add. 2549 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-SAME', 2550 epsilon_path) 2551 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-SAME', 2552 K_path) 2553 2554 # Created expected output tree for 'svn ci' 2555 expected_output = wc.State(wc_dir, { 2556 'A/B/upsilon' : Item(verb='Adding'), 2557 'A/C/nu' : Item(verb='Adding'), 2558 'A/D/kappa' : Item(verb='Adding'), 2559 'A/D/epsilon' : Item(verb='Adding'), 2560 'A/D/zeta' : Item(verb='Adding'), 2561 'A/D/H/I' : Item(verb='Adding'), 2562 'A/D/H/I/J' : Item(verb='Adding'), 2563 'A/D/H/I/J/eta' : Item(verb='Adding'), 2564 'A/D/H/I/K' : Item(verb='Adding'), 2565 'A/D/H/I/K/xi' : Item(verb='Adding'), 2566 'A/D/H/I/L' : Item(verb='Adding'), 2567 }) 2568 2569 # Create expected status tree. 2570 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 2571 expected_status.add({ 2572 'A/B/upsilon' : Item(status=' ', wc_rev=2), 2573 'A/C/nu' : Item(status=' ', wc_rev=2), 2574 'A/D/kappa' : Item(status=' ', wc_rev=2), 2575 'A/D/epsilon' : Item(status=' ', wc_rev=2), 2576 'A/D/zeta' : Item(status=' ', wc_rev=2), 2577 'A/D/H/I' : Item(status=' ', wc_rev=2), 2578 'A/D/H/I/J' : Item(status=' ', wc_rev=2), 2579 'A/D/H/I/J/eta' : Item(status=' ', wc_rev=2), 2580 'A/D/H/I/K' : Item(status=' ', wc_rev=2), 2581 'A/D/H/I/K/xi' : Item(status=' ', wc_rev=2), 2582 'A/D/H/I/L' : Item(status=' ', wc_rev=2), 2583 }) 2584 2585 # Commit. 2586 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 2587 expected_status) 2588 2589 # Create various paths scheduled for addition which will obstruct 2590 # the adds coming from the repos. 2591 upsilon_backup_path = os.path.join(wc_backup, 'A', 'B', 'upsilon') 2592 svntest.main.file_append(upsilon_backup_path, 2593 "This is the file 'upsilon'\n") 2594 kappa_backup_path = os.path.join(wc_backup, 'A', 'D', 'kappa') 2595 svntest.main.file_append(kappa_backup_path, 2596 "This is WC file 'kappa'\n") 2597 epsilon_backup_path = os.path.join(wc_backup, 'A', 'D', 'epsilon') 2598 svntest.main.file_append(epsilon_backup_path, 2599 "This is WC file 'epsilon'\n") 2600 zeta_backup_path = os.path.join(wc_backup, 'A', 'D', 'zeta') 2601 svntest.main.file_append(zeta_backup_path, "This is the file 'zeta'\n") 2602 I_backup_path = os.path.join(wc_backup, 'A', 'D', 'H', 'I') 2603 os.mkdir(I_backup_path) 2604 J_backup_path = os.path.join(I_backup_path, 'J') 2605 os.mkdir(J_backup_path) 2606 K_backup_path = os.path.join(I_backup_path, 'K') 2607 os.mkdir(K_backup_path) 2608 xi_backup_path = os.path.join(K_backup_path, 'xi') 2609 svntest.main.file_append(xi_backup_path, "This is the file 'xi'\n") 2610 eta_backup_path = os.path.join(J_backup_path, 'eta') 2611 svntest.main.file_append(eta_backup_path, "This is WC file 'eta'\n") 2612 2613 svntest.main.run_svn(None, 'add', upsilon_backup_path, kappa_backup_path, 2614 epsilon_backup_path, zeta_backup_path, I_backup_path) 2615 2616 # Set prop that will conflict with add from repos. 2617 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-WC', 2618 kappa_backup_path) 2619 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-WC', 2620 zeta_backup_path) 2621 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-WC', 2622 J_backup_path) 2623 2624 # Set prop that will match add from repos. 2625 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-SAME', 2626 epsilon_backup_path) 2627 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-SAME', 2628 K_backup_path) 2629 2630 # Create expected output tree for an update of the wc_backup. 2631 expected_output = wc.State(wc_backup, { 2632 'A/B/upsilon' : Item(status='E '), 2633 'A/C/nu' : Item(status='A '), 2634 'A/D/H/I' : Item(status='E '), 2635 'A/D/H/I/J' : Item(status='EC'), 2636 'A/D/H/I/J/eta' : Item(status='C '), 2637 'A/D/H/I/K' : Item(status='EG'), 2638 'A/D/H/I/K/xi' : Item(status='E '), 2639 'A/D/H/I/L' : Item(status='A '), 2640 'A/D/kappa' : Item(status='CC'), 2641 'A/D/epsilon' : Item(status='CG'), 2642 'A/D/zeta' : Item(status='EC'), 2643 }) 2644 2645 # Create expected disk for update of wc_backup. 2646 expected_disk = svntest.main.greek_state.copy() 2647 expected_disk.add({ 2648 'A/B/upsilon' : Item("This is the file 'upsilon'\n"), 2649 'A/C/nu' : Item("This is the file 'nu'\n"), 2650 'A/D/H/I' : Item(), 2651 'A/D/H/I/J' : Item(props={'propname1' : 'propval-WC'}), 2652 'A/D/H/I/J/eta' : Item("\n".join(["<<<<<<< .mine", 2653 "This is WC file 'eta'", 2654 "||||||| .r0", 2655 "=======", 2656 "This is REPOS file 'eta'", 2657 ">>>>>>> .r2", 2658 ""])), 2659 'A/D/H/I/K' : Item(props={'propname1' : 'propval-SAME'}), 2660 'A/D/H/I/K/xi' : Item("This is the file 'xi'\n"), 2661 'A/D/H/I/L' : Item(), 2662 'A/D/kappa' : Item("\n".join(["<<<<<<< .mine", 2663 "This is WC file 'kappa'", 2664 "||||||| .r0", 2665 "=======", 2666 "This is REPOS file 'kappa'", 2667 ">>>>>>> .r2", 2668 ""]), 2669 props={'propname1' : 'propval-WC'}), 2670 'A/D/epsilon' : Item("\n".join(["<<<<<<< .mine", 2671 "This is WC file 'epsilon'", 2672 "||||||| .r0", 2673 "=======", 2674 "This is REPOS file 'epsilon'", 2675 ">>>>>>> .r2", 2676 ""]), 2677 props={'propname1' : 'propval-SAME'}), 2678 'A/D/zeta' : Item("This is the file 'zeta'\n", 2679 props={'propname1' : 'propval-WC'}), 2680 }) 2681 2682 # Create expected status tree for the update. Since the obstructing 2683 # kappa and upsilon differ from the repos, they should show as modified. 2684 expected_status = svntest.actions.get_virginal_state(wc_backup, 2) 2685 expected_status.add({ 2686 'A/B/upsilon' : Item(status=' ', wc_rev=2), 2687 'A/C/nu' : Item(status=' ', wc_rev=2), 2688 'A/D/H/I' : Item(status=' ', wc_rev=2), 2689 'A/D/H/I/J' : Item(status=' C', wc_rev=2), 2690 'A/D/H/I/J/eta' : Item(status='C ', wc_rev=2), 2691 'A/D/H/I/K' : Item(status=' ', wc_rev=2), 2692 'A/D/H/I/K/xi' : Item(status=' ', wc_rev=2), 2693 'A/D/H/I/L' : Item(status=' ', wc_rev=2), 2694 'A/D/kappa' : Item(status='CC', wc_rev=2), 2695 'A/D/epsilon' : Item(status='C ', wc_rev=2), 2696 'A/D/zeta' : Item(status=' C', wc_rev=2), 2697 }) 2698 2699 # "Extra" files that we expect to result from the conflicts. 2700 extra_files = ['eta\.r0', 'eta\.r2', 'eta\.mine', 2701 'kappa\.r0', 'kappa\.r2', 'kappa\.mine', 2702 'epsilon\.r0', 'epsilon\.r2', 'epsilon\.mine', 2703 'kappa.prej', 'zeta.prej', 'dir_conflicts.prej'] 2704 2705 # Perform forced update and check the results in three 2706 # ways (including props). 2707 svntest.actions.run_and_verify_update(wc_backup, 2708 expected_output, 2709 expected_disk, 2710 expected_status, 2711 [], True, 2712 '--adds-as-modification', wc_backup, 2713 extra_files=extra_files) 2714 2715 # Some obstructions are still not permitted: 2716 # 2717 # Test that file and dir obstructions scheduled for addition *with* 2718 # history fail when update tries to add the same path. 2719 2720 # URL to URL copy of A/D/G to A/M. 2721 G_URL = sbox.repo_url + '/A/D/G' 2722 M_URL = sbox.repo_url + '/A/M' 2723 svntest.actions.run_and_verify_svn(None, [], 2724 'cp', G_URL, M_URL, '-m', '') 2725 2726 # WC to WC copy of A/D/H to A/M, M now scheduled for addition with 2727 # history in WC and pending addition from the repos. 2728 H_path = sbox.ospath('A/D/H') 2729 A_path = sbox.ospath('A') 2730 M_path = sbox.ospath('A/M') 2731 2732 svntest.actions.run_and_verify_svn(None, [], 2733 'cp', H_path, M_path) 2734 2735 # URL to URL copy of A/D/H/omega to omicron. 2736 omega_URL = sbox.repo_url + '/A/D/H/omega' 2737 omicron_URL = sbox.repo_url + '/omicron' 2738 svntest.actions.run_and_verify_svn(None, [], 2739 'cp', omega_URL, omicron_URL, 2740 '-m', '') 2741 2742 # WC to WC copy of A/D/H/chi to omicron, omicron now scheduled for 2743 # addition with history in WC and pending addition from the repos. 2744 chi_path = sbox.ospath('A/D/H/chi') 2745 omicron_path = sbox.ospath('omicron') 2746 2747 svntest.actions.run_and_verify_svn(None, [], 2748 'cp', chi_path, 2749 omicron_path) 2750 2751 # Try to update M's Parent. 2752 expected_output = wc.State(A_path, { 2753 'M' : Item(status=' ', treeconflict='C'), 2754 'M/rho' : Item(status=' ', treeconflict='A'), 2755 'M/pi' : Item(status=' ', treeconflict='A'), 2756 'M/tau' : Item(status=' ', treeconflict='A'), 2757 }) 2758 2759 expected_disk = svntest.main.greek_state.copy() 2760 expected_disk.add({ 2761 'A/B/upsilon' : Item("This is the file 'upsilon'\n"), 2762 'A/C/nu' : Item("This is the file 'nu'\n"), 2763 'A/D/H/I' : Item(), 2764 'A/D/H/I/J' : Item(), 2765 'A/D/H/I/J/eta' : Item("This is REPOS file 'eta'\n"), 2766 'A/D/H/I/K' : Item(), 2767 'A/D/H/I/K/xi' : Item("This is the file 'xi'\n"), 2768 'A/D/H/I/L' : Item(), 2769 'A/D/kappa' : Item("This is REPOS file 'kappa'\n"), 2770 'A/D/epsilon' : Item("This is REPOS file 'epsilon'\n"), 2771 'A/D/gamma' : Item("This is the file 'gamma'.\n"), 2772 'A/D/zeta' : Item("This is the file 'zeta'\n"), 2773 'A/M/I' : Item(), 2774 'A/M/I/J' : Item(), 2775 'A/M/I/J/eta' : Item("This is REPOS file 'eta'\n"), 2776 'A/M/I/K' : Item(), 2777 'A/M/I/K/xi' : Item("This is the file 'xi'\n"), 2778 'A/M/I/L' : Item(), 2779 'A/M/chi' : Item("This is the file 'chi'.\n"), 2780 'A/M/psi' : Item("This is the file 'psi'.\n"), 2781 'A/M/omega' : Item("This is the file 'omega'.\n"), 2782 'omicron' : Item("This is the file 'chi'.\n"), 2783 }) 2784 2785 expected_status = svntest.actions.get_virginal_state(wc_dir, 4) 2786 expected_status.tweak('', 'iota', wc_rev=1) 2787 expected_status.add({ 2788 'A/B/upsilon' : Item(status=' ', wc_rev=4), 2789 'A/C/nu' : Item(status=' ', wc_rev=4), 2790 'A/D/kappa' : Item(status=' ', wc_rev=4), 2791 'A/D/epsilon' : Item(status=' ', wc_rev=4), 2792 'A/D/gamma' : Item(status=' ', wc_rev=4), 2793 'A/D/zeta' : Item(status=' ', wc_rev=4), 2794 'A/D/H/I' : Item(status=' ', wc_rev=4), 2795 'A/D/H/I/J' : Item(status=' ', wc_rev=4), 2796 'A/D/H/I/J/eta' : Item(status=' ', wc_rev=4), 2797 'A/D/H/I/K' : Item(status=' ', wc_rev=4), 2798 'A/D/H/I/K/xi' : Item(status=' ', wc_rev=4), 2799 'A/D/H/I/L' : Item(status=' ', wc_rev=4), 2800 'A/M' : Item(status='R ', copied='+', wc_rev='-', 2801 treeconflict='C'), 2802 'A/M/I' : Item(status='A ', copied='+', wc_rev='-', 2803 entry_status=' '), # New op_root 2804 'A/M/I/J' : Item(status=' ', copied='+', wc_rev='-'), 2805 'A/M/I/J/eta' : Item(status=' ', copied='+', wc_rev='-'), 2806 'A/M/I/K' : Item(status=' ', copied='+', wc_rev='-'), 2807 'A/M/I/K/xi' : Item(status=' ', copied='+', wc_rev='-'), 2808 'A/M/I/L' : Item(status=' ', copied='+', wc_rev='-'), 2809 'A/M/chi' : Item(status=' ', copied='+', wc_rev='-'), 2810 'A/M/psi' : Item(status=' ', copied='+', wc_rev='-'), 2811 'A/M/omega' : Item(status=' ', copied='+', wc_rev='-'), 2812 'omicron' : Item(status='A ', copied='+', wc_rev='-'), 2813 2814 # Inserted under the tree conflict 2815 'A/M/pi' : Item(status='D ', wc_rev='4'), 2816 'A/M/rho' : Item(status='D ', wc_rev='4'), 2817 'A/M/tau' : Item(status='D ', wc_rev='4'), 2818 }) 2819 2820 svntest.actions.run_and_verify_update(wc_dir, expected_output, 2821 expected_disk, expected_status, 2822 [], False, 2823 '--adds-as-modification', 2824 A_path) 2825 2826 # Resolve the tree conflict. 2827 svntest.main.run_svn(None, 'resolve', '--accept', 'working', M_path) 2828 2829 # Try to update omicron's parent, non-recusively so as not to 2830 # try and update M first. 2831 expected_output = wc.State(wc_dir, { 2832 'omicron' : Item(status=' ', treeconflict='C'), 2833 }) 2834 2835 expected_status.tweak('', 'iota', status=' ', wc_rev=4) 2836 expected_status.tweak('omicron', status='R ', copied='+', wc_rev='-', 2837 treeconflict='C') 2838 expected_status.tweak('A/M', treeconflict=None) 2839 2840 svntest.actions.run_and_verify_update(wc_dir, expected_output, 2841 expected_disk, expected_status, 2842 [], False, 2843 wc_dir, '-N', '--adds-as-modification') 2844 2845 # Resolve the tree conflict. 2846 svntest.main.run_svn(None, 'resolved', omicron_path) 2847 2848 expected_output = wc.State(wc_dir, { }) 2849 2850 expected_status.tweak('omicron', treeconflict=None) 2851 2852 # Again, --force shouldn't matter. 2853 svntest.actions.run_and_verify_update(wc_dir, expected_output, 2854 expected_disk, expected_status, 2855 [], False, 2856 omicron_path, '-N', '--force') 2857 2858# Test for issue #2022: Update shouldn't touch conflicted files. 2859def update_conflicted(sbox): 2860 "update conflicted files" 2861 sbox.build() 2862 wc_dir = sbox.wc_dir 2863 iota_path = sbox.ospath('iota') 2864 lambda_path = sbox.ospath('A/B/lambda') 2865 mu_path = sbox.ospath('A/mu') 2866 D_path = sbox.ospath('A/D') 2867 pi_path = sbox.ospath('A/D/G/pi') 2868 2869 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 2870 2871 # Make some modifications to the files and a dir, creating r2. 2872 svntest.main.file_append(iota_path, 'Original appended text for iota\n') 2873 2874 svntest.main.run_svn(None, 'propset', 'prop', 'val', lambda_path) 2875 2876 svntest.main.file_append(mu_path, 'Original appended text for mu\n') 2877 2878 svntest.main.run_svn(None, 'propset', 'prop', 'val', mu_path) 2879 svntest.main.run_svn(None, 'propset', 'prop', 'val', D_path) 2880 2881 expected_output = svntest.wc.State(wc_dir, { 2882 'iota' : Item(verb='Sending'), 2883 'A/mu': Item(verb='Sending'), 2884 'A/B/lambda': Item(verb='Sending'), 2885 'A/D': Item(verb='Sending'), 2886 }) 2887 2888 expected_status.tweak('iota', 'A/mu', 'A/B/lambda', 'A/D', wc_rev=2) 2889 2890 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 2891 expected_status) 2892 2893 # Do another change to each path that we will need later. 2894 # Also, change a file below A/D in the path. 2895 svntest.main.file_append(iota_path, 'Another line for iota\n') 2896 svntest.main.file_append(mu_path, 'Another line for mu\n') 2897 svntest.main.file_append(lambda_path, 'Another line for lambda\n') 2898 2899 svntest.main.run_svn(None, 'propset', 'prop', 'val2', D_path) 2900 2901 svntest.main.file_append(pi_path, 'Another line for pi\n') 2902 2903 expected_status.tweak('iota', 'A/mu', 'A/B/lambda', 'A/D', 'A/D/G/pi', 2904 wc_rev=3) 2905 2906 expected_output.add({ 2907 'A/D/G/pi': Item(verb='Sending')}) 2908 2909 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 2910 expected_status) 2911 2912 # Go back to revision 1. 2913 expected_output = svntest.wc.State(wc_dir, { 2914 'iota' : Item(status='U '), 2915 'A/B/lambda' : Item(status='UU'), 2916 'A/mu' : Item(status='UU'), 2917 'A/D': Item(status=' U'), 2918 'A/D/G/pi': Item(status='U '), 2919 }) 2920 2921 expected_disk = svntest.main.greek_state.copy() 2922 2923 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 2924 2925 svntest.actions.run_and_verify_update(wc_dir, 2926 expected_output, 2927 expected_disk, 2928 expected_status, 2929 [], True, 2930 '-r1', wc_dir) 2931 2932 # Create modifications conflicting with rev 2. 2933 svntest.main.file_append(iota_path, 'Conflicting appended text for iota\n') 2934 svntest.main.run_svn(None, 'propset', 'prop', 'conflictval', lambda_path) 2935 svntest.main.file_append(mu_path, 'Conflicting appended text for mu\n') 2936 svntest.main.run_svn(None, 'propset', 'prop', 'conflictval', mu_path) 2937 svntest.main.run_svn(None, 'propset', 'prop', 'conflictval', D_path) 2938 2939 # Update to revision 2, expecting conflicts. 2940 expected_output = svntest.wc.State(wc_dir, { 2941 'iota': Item(status='C '), 2942 'A/B/lambda': Item(status=' C'), 2943 'A/mu': Item(status='CC'), 2944 'A/D': Item(status=' C'), 2945 }) 2946 2947 expected_disk.tweak('iota', 2948 contents="\n".join(["This is the file 'iota'.", 2949 "<<<<<<< .mine", 2950 "Conflicting appended text for iota", 2951 "||||||| .r1", 2952 "=======", 2953 "Original appended text for iota", 2954 ">>>>>>> .r2", 2955 ""])) 2956 expected_disk.tweak('A/mu', 2957 contents="\n".join(["This is the file 'mu'.", 2958 "<<<<<<< .mine", 2959 "Conflicting appended text for mu", 2960 "||||||| .r1", 2961 "=======", 2962 "Original appended text for mu", 2963 ">>>>>>> .r2", 2964 ""]), 2965 props={'prop': 'conflictval'}) 2966 expected_disk.tweak('A/B/lambda', 'A/D', props={'prop': 'conflictval'}) 2967 2968 expected_status.tweak(wc_rev=2) 2969 expected_status.tweak('iota', status='C ') 2970 expected_status.tweak('A/B/lambda', 'A/D', status=' C') 2971 expected_status.tweak('A/mu', status='CC') 2972 2973 extra_files = [ 'iota.r1', 'iota.r2', 'iota.mine', 2974 'mu.r1', 'mu.r2', 'mu.mine', 'mu.prej', 2975 'lambda.prej', 2976 'dir_conflicts.prej'] 2977 2978 svntest.actions.run_and_verify_update(wc_dir, 2979 expected_output, 2980 expected_disk, 2981 expected_status, 2982 [], True, 2983 '-r2', wc_dir, 2984 extra_files=extra_files+[]) 2985 2986 # Now, update to HEAD, which should skip all the conflicted files, but 2987 # still update the pi file. 2988 expected_output = svntest.wc.State(wc_dir, { 2989 'iota' : Item(verb='Skipped'), 2990 'A/B/lambda' : Item(verb='Skipped'), 2991 'A/mu' : Item(verb='Skipped'), 2992 'A/D' : Item(verb='Skipped'), 2993 }) 2994 2995 expected_status.tweak(wc_rev=3) 2996 expected_status.tweak('iota', 'A/B/lambda', 'A/mu', 'A/D', wc_rev=2) 2997 # We no longer update descendants of a prop-conflicted dir. 2998 expected_status.tweak('A/D/G', 2999 'A/D/G/pi', 3000 'A/D/G/rho', 3001 'A/D/G/tau', 3002 'A/D/H', 3003 'A/D/H/chi', 3004 'A/D/H/omega', 3005 'A/D/H/psi', 3006 'A/D/gamma', wc_rev=2) 3007 3008 svntest.actions.run_and_verify_update(wc_dir, 3009 expected_output, 3010 expected_disk, 3011 expected_status, 3012 [], True, 3013 extra_files=extra_files) 3014 3015#---------------------------------------------------------------------- 3016@SkipUnless(server_has_mergeinfo) 3017def mergeinfo_update_elision(sbox): 3018 "mergeinfo does not elide after update" 3019 3020 # No mergeinfo elision is performed when doing updates. So updates may 3021 # result in equivalent mergeinfo on a path and it's nearest working copy 3022 # parent with explicit mergeinfo. This is currently permitted and 3023 # honestly we could probably do without this test(?). 3024 3025 sbox.build() 3026 wc_dir = sbox.wc_dir 3027 3028 # Some paths we'll care about 3029 alpha_COPY_path = sbox.ospath('A/B_COPY/E/alpha') 3030 alpha_path = sbox.ospath('A/B/E/alpha') 3031 B_COPY_path = sbox.ospath('A/B_COPY') 3032 E_COPY_path = sbox.ospath('A/B_COPY/E') 3033 beta_path = sbox.ospath('A/B/E/beta') 3034 lambda_path = sbox.ospath('A/B/lambda') 3035 3036 # Make a branch A/B_COPY 3037 expected_stdout = verify.UnorderedOutput([ 3038 "A " + B_COPY_path + "\n", 3039 "A " + sbox.ospath('A/B_COPY/lambda') + "\n", 3040 "A " + sbox.ospath('A/B_COPY/E') + "\n", 3041 "A " + sbox.ospath('A/B_COPY/E/alpha') + "\n", 3042 "A " + sbox.ospath('A/B_COPY/E/beta') + "\n", 3043 "A " + sbox.ospath('A/B_COPY/F') + "\n", 3044 ]) 3045 svntest.actions.run_and_verify_svn(expected_stdout, [], 'copy', 3046 sbox.repo_url + "/A/B", B_COPY_path) 3047 3048 expected_output = wc.State(wc_dir, {'A/B_COPY' : Item(verb='Adding')}) 3049 3050 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 3051 expected_status.add({ 3052 "A/B_COPY" : Item(status=' ', wc_rev=2), 3053 "A/B_COPY/lambda" : Item(status=' ', wc_rev=2), 3054 "A/B_COPY/E" : Item(status=' ', wc_rev=2), 3055 "A/B_COPY/E/alpha" : Item(status=' ', wc_rev=2), 3056 "A/B_COPY/E/beta" : Item(status=' ', wc_rev=2), 3057 "A/B_COPY/F" : Item(status=' ', wc_rev=2),}) 3058 3059 svntest.actions.run_and_verify_commit(wc_dir, 3060 expected_output, 3061 expected_status) 3062 3063 # Make some changes under A/B 3064 3065 # r3 - modify and commit A/B/E/beta 3066 svntest.main.file_write(beta_path, "New content") 3067 3068 expected_output = wc.State(wc_dir, {'A/B/E/beta' : Item(verb='Sending')}) 3069 3070 expected_status.tweak('A/B/E/beta', wc_rev=3) 3071 3072 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 3073 expected_status) 3074 3075 # r4 - modify and commit A/B/lambda 3076 svntest.main.file_write(lambda_path, "New content") 3077 3078 expected_output = wc.State(wc_dir, {'A/B/lambda' : Item(verb='Sending')}) 3079 3080 expected_status.tweak('A/B/lambda', wc_rev=4) 3081 3082 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 3083 expected_status) 3084 3085 # r5 - modify and commit A/B/E/alpha 3086 svntest.main.file_write(alpha_path, "New content") 3087 3088 expected_output = wc.State(wc_dir, {'A/B/E/alpha' : Item(verb='Sending')}) 3089 3090 expected_status.tweak('A/B/E/alpha', wc_rev=5) 3091 3092 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 3093 expected_status) 3094 3095 # Merge r2:5 into A/B_COPY 3096 expected_output = wc.State(B_COPY_path, { 3097 'lambda' : Item(status='U '), 3098 'E/alpha' : Item(status='U '), 3099 'E/beta' : Item(status='U '), 3100 }) 3101 3102 expected_mergeinfo_output = wc.State(B_COPY_path, { 3103 '' : Item(status=' U'), 3104 }) 3105 3106 expected_elision_output = wc.State(B_COPY_path, { 3107 }) 3108 3109 expected_merge_status = wc.State(B_COPY_path, { 3110 '' : Item(status=' M', wc_rev=2), 3111 'lambda' : Item(status='M ', wc_rev=2), 3112 'E' : Item(status=' ', wc_rev=2), 3113 'E/alpha' : Item(status='M ', wc_rev=2), 3114 'E/beta' : Item(status='M ', wc_rev=2), 3115 'F' : Item(status=' ', wc_rev=2), 3116 }) 3117 3118 expected_merge_disk = wc.State('', { 3119 '' : Item(props={SVN_PROP_MERGEINFO : '/A/B:3-5'}), 3120 'lambda' : Item("New content"), 3121 'E' : Item(), 3122 'E/alpha' : Item("New content"), 3123 'E/beta' : Item("New content"), 3124 'F' : Item(), 3125 }) 3126 3127 expected_skip = wc.State(B_COPY_path, { }) 3128 3129 svntest.actions.run_and_verify_merge(B_COPY_path, '2', '5', 3130 sbox.repo_url + '/A/B', None, 3131 expected_output, 3132 expected_mergeinfo_output, 3133 expected_elision_output, 3134 expected_merge_disk, 3135 expected_merge_status, 3136 expected_skip, 3137 check_props=True) 3138 3139 # r6 - Commit the merge 3140 expected_output = wc.State(wc_dir, 3141 {'A/B_COPY' : Item(verb='Sending'), 3142 'A/B_COPY/E/alpha' : Item(verb='Sending'), 3143 'A/B_COPY/E/beta' : Item(verb='Sending'), 3144 'A/B_COPY/lambda' : Item(verb='Sending')}) 3145 3146 expected_status.tweak('A/B_COPY', wc_rev=6) 3147 expected_status.tweak('A/B_COPY/E/alpha', wc_rev=6) 3148 expected_status.tweak('A/B_COPY/E/beta', wc_rev=6) 3149 expected_status.tweak('A/B_COPY/lambda', wc_rev=6) 3150 3151 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 3152 expected_status) 3153 3154 # Update WC back to r5, A/COPY_B is at it's pre-merge state again 3155 expected_output = wc.State(wc_dir, 3156 {'A/B_COPY' : Item(status=' U'), 3157 'A/B_COPY/E/alpha' : Item(status='U '), 3158 'A/B_COPY/E/beta' : Item(status='U '), 3159 'A/B_COPY/lambda' : Item(status='U '),}) 3160 3161 expected_status.tweak(wc_rev=5) 3162 3163 expected_disk = svntest.main.greek_state.copy() 3164 expected_disk.add({ 3165 'A/B_COPY' : Item(), 3166 'A/B_COPY/lambda' : Item("This is the file 'lambda'.\n"), 3167 'A/B_COPY/E' : Item(), 3168 'A/B_COPY/E/alpha' : Item("This is the file 'alpha'.\n"), 3169 'A/B_COPY/E/beta' : Item("This is the file 'beta'.\n"), 3170 'A/B_COPY/F' : Item(), 3171 }) 3172 expected_disk.tweak('A/B/lambda', contents="New content") 3173 expected_disk.tweak('A/B/E/alpha', contents="New content") 3174 expected_disk.tweak('A/B/E/beta', contents="New content") 3175 3176 svntest.actions.run_and_verify_update(wc_dir, 3177 expected_output, 3178 expected_disk, 3179 expected_status, 3180 [], True, 3181 '-r', '5', wc_dir) 3182 3183 # Merge r2:5 to A/B_COPY/E/alpha 3184 expected_output = wc.State(alpha_COPY_path, { 3185 'alpha' : Item(status='U '), 3186 }) 3187 expected_skip = wc.State(alpha_COPY_path, { }) 3188 3189 # run_and_verify_merge doesn't support merging to a file WCPATH 3190 # so use run_and_verify_svn. 3191 svntest.actions.run_and_verify_svn(expected_merge_output([[3,5]], 3192 ['U ' + alpha_COPY_path + '\n', 3193 ' U ' + alpha_COPY_path + '\n']), 3194 [], 'merge', '-r2:5', 3195 sbox.repo_url + '/A/B/E/alpha', 3196 alpha_COPY_path) 3197 3198 3199 expected_alpha_status = wc.State(alpha_COPY_path, { 3200 '' : Item(status='MM', wc_rev=5), 3201 }) 3202 3203 svntest.actions.run_and_verify_status(alpha_COPY_path, 3204 expected_alpha_status) 3205 3206 svntest.actions.run_and_verify_svn(["/A/B/E/alpha:3-5\n"], [], 3207 'propget', SVN_PROP_MERGEINFO, 3208 alpha_COPY_path) 3209 3210 # Update WC. The local mergeinfo (r3-5) on A/B_COPY/E/alpha is 3211 # identical to that on added to A/B_COPY by the update, but update 3212 # doesn't support elision so this redundancy is permitted. 3213 expected_output = wc.State(wc_dir, { 3214 'A/B_COPY/lambda' : Item(status='U '), 3215 'A/B_COPY/E/alpha' : Item(status='G '), 3216 'A/B_COPY/E/beta' : Item(status='U '), 3217 'A/B_COPY' : Item(status=' U'), 3218 }) 3219 3220 expected_disk.tweak('A/B_COPY', props={SVN_PROP_MERGEINFO : '/A/B:3-5'}) 3221 expected_disk.tweak('A/B_COPY/lambda', contents="New content") 3222 expected_disk.tweak('A/B_COPY/E/beta', contents="New content") 3223 expected_disk.tweak('A/B_COPY/E/alpha', contents="New content", 3224 props={SVN_PROP_MERGEINFO : '/A/B/E/alpha:3-5'}) 3225 3226 expected_status.tweak(wc_rev=6) 3227 expected_status.tweak('A/B_COPY/E/alpha', status=' M') 3228 3229 svntest.actions.run_and_verify_update(wc_dir, 3230 expected_output, 3231 expected_disk, 3232 expected_status, 3233 [], True) 3234 3235 # Now test that an updated target's mergeinfo can itself elide. 3236 # r7 - modify and commit A/B/E/alpha 3237 svntest.main.file_write(alpha_path, "More new content") 3238 expected_output = wc.State(wc_dir, { 3239 'A/B/E/alpha' : Item(verb='Sending'), 3240 'A/B_COPY/E/alpha' : Item(verb='Sending')}) 3241 expected_status.tweak('A/B/E/alpha', 'A/B_COPY/E/alpha', status=' ', 3242 wc_rev=7) 3243 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 3244 expected_status) 3245 3246 # Update A to get all paths to the same working revision. 3247 svntest.actions.run_and_verify_svn(exp_noop_up_out(7), [], 3248 'up', wc_dir) 3249 3250 # Merge r6:7 into A/B_COPY/E 3251 expected_output = wc.State(E_COPY_path, { 3252 'alpha' : Item(status='U '), 3253 }) 3254 3255 expected_mergeinfo_output = wc.State(E_COPY_path, { 3256 '' : Item(status=' G'), 3257 'alpha' : Item(status=' U'), 3258 }) 3259 3260 expected_elision_output = wc.State(E_COPY_path, { 3261 'alpha' : Item(status=' U'), 3262 }) 3263 3264 expected_merge_status = wc.State(E_COPY_path, { 3265 '' : Item(status=' M', wc_rev=7), 3266 'alpha' : Item(status='MM', wc_rev=7), 3267 'beta' : Item(status=' ', wc_rev=7), 3268 }) 3269 3270 expected_merge_disk = wc.State('', { 3271 '' : Item(props={SVN_PROP_MERGEINFO : '/A/B/E:3-5,7'}), 3272 'alpha' : Item("More new content"), 3273 'beta' : Item("New content"), 3274 }) 3275 3276 expected_skip = wc.State(E_COPY_path, { }) 3277 3278 svntest.actions.run_and_verify_merge(E_COPY_path, '6', '7', 3279 sbox.repo_url + '/A/B/E', None, 3280 expected_output, 3281 expected_mergeinfo_output, 3282 expected_elision_output, 3283 expected_merge_disk, 3284 expected_merge_status, 3285 expected_skip, 3286 check_props=True) 3287 3288 # r8 - Commit the merge 3289 svntest.actions.run_and_verify_svn(exp_noop_up_out(7), 3290 [], 'update', wc_dir) 3291 3292 expected_output = wc.State(wc_dir, 3293 {'A/B_COPY/E' : Item(verb='Sending'), 3294 'A/B_COPY/E/alpha' : Item(verb='Sending')}) 3295 3296 expected_status.tweak(wc_rev=7) 3297 expected_status.tweak('A/B_COPY/E', 'A/B_COPY/E/alpha', wc_rev=8) 3298 3299 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 3300 expected_status) 3301 3302 # Update A/COPY_B/E back to r7 3303 expected_output = wc.State(wc_dir, { 3304 'A/B_COPY/E/alpha' : Item(status='UU'), 3305 'A/B_COPY/E' : Item(status=' U'), 3306 }) 3307 3308 expected_status.tweak(wc_rev=7) 3309 3310 expected_disk.tweak('A/B_COPY', 3311 props={SVN_PROP_MERGEINFO : '/A/B:3-5'}) 3312 expected_disk.tweak('A/B/E/alpha', contents="More new content") 3313 expected_disk.tweak('A/B_COPY/E/alpha', contents="New content") 3314 3315 svntest.actions.run_and_verify_update(wc_dir, 3316 expected_output, 3317 expected_disk, 3318 expected_status, 3319 [], True, 3320 '-r', '7', E_COPY_path) 3321 3322 # Merge r6:7 to A/B_COPY 3323 expected_output = wc.State(B_COPY_path, { 3324 'E/alpha' : Item(status='U '), 3325 }) 3326 3327 expected_mergeinfo_output = wc.State(B_COPY_path, { 3328 '' : Item(status=' U'), 3329 'E/alpha' : Item(status=' U'), 3330 }) 3331 3332 expected_elision_output = wc.State(B_COPY_path, { 3333 'E/alpha' : Item(status=' U'), 3334 }) 3335 3336 expected_merge_status = wc.State(B_COPY_path, { 3337 '' : Item(status=' M', wc_rev=7), 3338 'lambda' : Item(status=' ', wc_rev=7), 3339 'E' : Item(status=' ', wc_rev=7), 3340 'E/alpha' : Item(status='MM', wc_rev=7), 3341 'E/beta' : Item(status=' ', wc_rev=7), 3342 'F' : Item(status=' ', wc_rev=7), 3343 }) 3344 3345 expected_merge_disk = wc.State('', { 3346 '' : Item(props={SVN_PROP_MERGEINFO : '/A/B:3-5,7'}), 3347 'lambda' : Item("New content"), 3348 'E' : Item(), 3349 'E/alpha' : Item("More new content"), 3350 'E/beta' : Item("New content"), 3351 'F' : Item(), 3352 }) 3353 3354 expected_skip = wc.State(B_COPY_path, { }) 3355 3356 svntest.actions.run_and_verify_merge(B_COPY_path, '6', '7', 3357 sbox.repo_url + '/A/B', None, 3358 expected_output, 3359 expected_mergeinfo_output, 3360 expected_elision_output, 3361 expected_merge_disk, 3362 expected_merge_status, 3363 expected_skip, 3364 [], True, True) 3365 3366 # Update just A/B_COPY/E. The mergeinfo (r3-5,7) reset on 3367 # A/B_COPY/E by the udpate is identical to the local info on 3368 # A/B_COPY, so should elide, leaving no mereginfo on E. 3369 expected_output = wc.State(wc_dir, { 3370 'A/B_COPY/E/alpha' : Item(status='GG'), 3371 'A/B_COPY/E/' : Item(status=' U'), 3372 }) 3373 3374 expected_status.tweak('A/B_COPY', status=' M', wc_rev=7) 3375 expected_status.tweak('A/B_COPY/E', status=' ', wc_rev=8) 3376 expected_status.tweak('A/B_COPY/E/alpha', wc_rev=8) 3377 expected_status.tweak('A/B_COPY/E/beta', wc_rev=8) 3378 3379 expected_disk.tweak('A/B_COPY', 3380 props={SVN_PROP_MERGEINFO : '/A/B:3-5,7'}) 3381 expected_disk.tweak('A/B_COPY/E', 3382 props={SVN_PROP_MERGEINFO : '/A/B/E:3-5,7'}) 3383 expected_disk.tweak('A/B_COPY/E/alpha', contents="More new content", 3384 props={}) 3385 3386 svntest.actions.run_and_verify_update(wc_dir, 3387 expected_output, 3388 expected_disk, 3389 expected_status, 3390 [], True, 3391 E_COPY_path) 3392 3393 3394#---------------------------------------------------------------------- 3395# Very obscure bug: Issue #2977. 3396# Let's say there's a revision with 3397# $ svn mv b c 3398# $ svn mv a b 3399# $ svn ci 3400# and a later revision that modifies b. We then try a fresh checkout. If 3401# the server happens to send us 'b' first, then when it later gets 'c' 3402# (with a copyfrom of 'b') it might try to use the 'b' in the wc as the 3403# copyfrom base. This is wrong, because 'b' was changed later; however, 3404# due to a bug, the setting of svn:entry:committed-rev on 'b' is not being 3405# properly seen by the client, and it chooses the wrong base. Corruption! 3406# 3407# Note that because this test depends on the order that the server sends 3408# changes, it is very fragile; even changing the file names can avoid 3409# triggering the bug. 3410 3411def update_copied_from_replaced_and_changed(sbox): 3412 "update chooses right copyfrom for double move" 3413 3414 sbox.build() 3415 wc_dir = sbox.wc_dir 3416 3417 fn1_relpath = 'A/B/E/aardvark' 3418 fn2_relpath = 'A/B/E/alpha' 3419 fn3_relpath = 'A/B/E/beta' 3420 fn1_path = sbox.ospath(fn1_relpath) 3421 fn2_path = sbox.ospath(fn2_relpath) 3422 fn3_path = sbox.ospath(fn3_relpath) 3423 3424 # Move fn2 to fn1 3425 svntest.actions.run_and_verify_svn(None, [], 3426 'mv', fn2_path, fn1_path) 3427 3428 # Move fn3 to fn2 3429 svntest.actions.run_and_verify_svn(None, [], 3430 'mv', fn3_path, fn2_path) 3431 3432 # Commit that change, creating r2. 3433 expected_output = svntest.wc.State(wc_dir, { 3434 fn1_relpath : Item(verb='Adding'), 3435 fn2_relpath : Item(verb='Replacing'), 3436 fn3_relpath : Item(verb='Deleting'), 3437 }) 3438 3439 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 3440 expected_status.remove(fn2_relpath, fn3_relpath) 3441 expected_status.add({ 3442 fn1_relpath : Item(status=' ', wc_rev=2), 3443 fn2_relpath : Item(status=' ', wc_rev=2), 3444 }) 3445 3446 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 3447 expected_status) 3448 3449 # Modify fn2. 3450 fn2_final_contents = "I have new contents for the middle file." 3451 svntest.main.file_write(fn2_path, fn2_final_contents) 3452 3453 # Commit the changes, creating r3. 3454 expected_output = svntest.wc.State(wc_dir, { 3455 fn2_relpath : Item(verb='Sending'), 3456 }) 3457 3458 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 3459 expected_status.remove(fn2_relpath, fn3_relpath) 3460 expected_status.add({ 3461 fn1_relpath : Item(status=' ', wc_rev=2), 3462 fn2_relpath : Item(status=' ', wc_rev=3), 3463 }) 3464 3465 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 3466 expected_status) 3467 3468 # Go back to r1. 3469 expected_output = svntest.wc.State(wc_dir, { 3470 fn1_relpath: Item(status='D '), 3471 fn2_relpath: Item(status='A ', prev_status='D '), # D then A 3472 fn3_relpath: Item(status='A '), 3473 }) 3474 3475 # Create expected disk tree for the update to rev 0 3476 expected_disk = svntest.main.greek_state.copy() 3477 3478 # Do the update and check the results. 3479 svntest.actions.run_and_verify_update(wc_dir, 3480 expected_output, 3481 expected_disk, 3482 None, 3483 [], False, 3484 '-r', '1', wc_dir) 3485 3486 # And back up to 3 again. 3487 expected_output = svntest.wc.State(wc_dir, { 3488 fn1_relpath: Item(status='A '), 3489 fn2_relpath: Item(status='A ', prev_status='D '), # D then A 3490 fn3_relpath: Item(status='D '), 3491 }) 3492 3493 # Create expected disk tree for the update to rev 0 3494 expected_disk = svntest.main.greek_state.copy() 3495 expected_disk.add({ 3496 fn1_relpath : Item("This is the file 'alpha'.\n"), 3497 }) 3498 expected_disk.tweak(fn2_relpath, contents=fn2_final_contents) 3499 expected_disk.remove(fn3_relpath) 3500 3501 # reuse old expected_status, but at r3 3502 expected_status.tweak(wc_rev=3) 3503 3504 svntest.actions.run_and_verify_update(wc_dir, 3505 expected_output, 3506 expected_disk, 3507 expected_status) 3508 3509#---------------------------------------------------------------------- 3510# Regression test: ra_neon assumes that you never delete a property on 3511# a newly-added file, which is wrong if it's add-with-history. 3512def update_copied_and_deleted_prop(sbox): 3513 "updating a copied file with a deleted property" 3514 3515 sbox.build() 3516 wc_dir = sbox.wc_dir 3517 iota_path = sbox.ospath('iota') 3518 iota2_path = sbox.ospath('iota2') 3519 3520 # Add a property on iota 3521 svntest.actions.run_and_verify_svn(None, [], 3522 'propset', 'foo', 'bar', iota_path) 3523 # Commit that change, creating r2. 3524 expected_output = svntest.wc.State(wc_dir, { 3525 'iota' : Item(verb='Sending'), 3526 }) 3527 3528 expected_status_mixed = svntest.actions.get_virginal_state(wc_dir, 1) 3529 expected_status_mixed.tweak('iota', wc_rev=2) 3530 3531 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 3532 expected_status_mixed) 3533 3534 # Copy iota to iota2 and delete the property on it. 3535 svntest.actions.run_and_verify_svn(None, [], 3536 'copy', iota_path, iota2_path) 3537 svntest.actions.run_and_verify_svn(None, [], 3538 'propdel', 'foo', iota2_path) 3539 3540 # Commit that change, creating r3. 3541 expected_output = svntest.wc.State(wc_dir, { 3542 'iota2' : Item(verb='Adding'), 3543 }) 3544 3545 expected_status_mixed.add({ 3546 'iota2' : Item(status=' ', wc_rev=3), 3547 }) 3548 3549 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 3550 expected_status_mixed) 3551 3552 # Update the whole wc, verifying disk as well. 3553 expected_output = svntest.wc.State(wc_dir, { }) 3554 3555 expected_disk_r3 = svntest.main.greek_state.copy() 3556 expected_disk_r3.add({ 3557 'iota2' : Item("This is the file 'iota'.\n"), 3558 }) 3559 expected_disk_r3.tweak('iota', props={'foo':'bar'}) 3560 3561 expected_status_r3 = expected_status_mixed.copy() 3562 expected_status_r3.tweak(wc_rev=3) 3563 3564 svntest.actions.run_and_verify_update(wc_dir, 3565 expected_output, 3566 expected_disk_r3, 3567 expected_status_r3, 3568 check_props=True) 3569 3570 # Now go back to r2. 3571 expected_output = svntest.wc.State(wc_dir, {'iota2': Item(status='D ')}) 3572 3573 expected_disk_r2 = expected_disk_r3.copy() 3574 expected_disk_r2.remove('iota2') 3575 3576 expected_status_r2 = expected_status_r3.copy() 3577 expected_status_r2.tweak(wc_rev=2) 3578 expected_status_r2.remove('iota2') 3579 3580 svntest.actions.run_and_verify_update(wc_dir, 3581 expected_output, 3582 expected_disk_r2, 3583 expected_status_r2, 3584 [], True, 3585 "-r2", wc_dir) 3586 3587 # And finally, back to r3, getting an add-with-history-and-property-deleted 3588 expected_output = svntest.wc.State(wc_dir, {'iota2': Item(status='A ')}) 3589 3590 svntest.actions.run_and_verify_update(wc_dir, 3591 expected_output, 3592 expected_disk_r3, 3593 expected_status_r3, 3594 check_props=True) 3595 3596#---------------------------------------------------------------------- 3597 3598def update_output_with_conflicts(rev, target, paths=None, resolved=False): 3599 """Return the expected output for an update of TARGET to revision REV, in 3600 which all of the PATHS are updated and conflicting. 3601 3602 If PATHS is None, it means [TARGET]. The output is a list of lines. 3603 """ 3604 if paths is None: 3605 paths = [target] 3606 3607 lines = ["Updating '%s':\n" % target] 3608 for path in paths: 3609 lines += ['C %s\n' % path] 3610 lines += ['Updated to revision %d.\n' % rev] 3611 if resolved: 3612 for path in paths: 3613 lines += ["Merge conflicts in '%s' marked as resolved.\n" % path] 3614 lines += svntest.main.summary_of_conflicts(text_resolved=len(paths)) 3615 else: 3616 lines += svntest.main.summary_of_conflicts(text_conflicts=len(paths)) 3617 return lines 3618 3619def update_output_with_conflicts_resolved(rev, target, paths=None): 3620 """Like update_output_with_conflicts(), but where all of the conflicts are 3621 resolved within the update. 3622 """ 3623 lines = update_output_with_conflicts(rev, target, paths, resolved=True) 3624 return lines 3625 3626#---------------------------------------------------------------------- 3627 3628def update_accept_conflicts(sbox): 3629 "update --accept automatic conflict resolution" 3630 3631 sbox.build() 3632 wc_dir = sbox.wc_dir 3633 3634 # Make a few local mods to files which will be committed 3635 iota_path = sbox.ospath('iota') 3636 lambda_path = sbox.ospath('A/B/lambda') 3637 mu_path = sbox.ospath('A/mu') 3638 alpha_path = sbox.ospath('A/B/E/alpha') 3639 beta_path = sbox.ospath('A/B/E/beta') 3640 pi_path = sbox.ospath('A/D/G/pi') 3641 p_i_path = sbox.ospath('A/D/G/p; i') 3642 rho_path = sbox.ospath('A/D/G/rho') 3643 3644 # Rename pi to "p; i" so we can exercise SVN_EDITOR's handling of paths with 3645 # special characters 3646 sbox.simple_move('A/D/G/pi', 'A/D/G/p; i') 3647 sbox.simple_commit() 3648 sbox.simple_update() 3649 3650 # Make a backup copy of the working copy 3651 wc_backup = sbox.add_wc_path('backup') 3652 svntest.actions.duplicate_dir(wc_dir, wc_backup) 3653 3654 svntest.main.file_append(lambda_path, 'Their appended text for lambda\n') 3655 svntest.main.file_append(iota_path, 'Their appended text for iota\n') 3656 svntest.main.file_append(mu_path, 'Their appended text for mu\n') 3657 svntest.main.file_append(alpha_path, 'Their appended text for alpha\n') 3658 svntest.main.file_append(beta_path, 'Their appended text for beta\n') 3659 svntest.main.file_append(p_i_path, 'Their appended text for pi\n') 3660 svntest.main.file_append(rho_path, 'Their appended text for rho\n') 3661 3662 # Make a few local mods to files which will be conflicted 3663 iota_path_backup = os.path.join(wc_backup, 'iota') 3664 lambda_path_backup = os.path.join(wc_backup, 'A', 'B', 'lambda') 3665 mu_path_backup = os.path.join(wc_backup, 'A', 'mu') 3666 alpha_path_backup = os.path.join(wc_backup, 'A', 'B', 'E', 'alpha') 3667 beta_path_backup = os.path.join(wc_backup, 'A', 'B', 'E', 'beta') 3668 p_i_path_backup = os.path.join(wc_backup, 'A', 'D', 'G', 'p; i') 3669 rho_path_backup = os.path.join(wc_backup, 'A', 'D', 'G', 'rho') 3670 svntest.main.file_append(iota_path_backup, 3671 'My appended text for iota\n') 3672 svntest.main.file_append(lambda_path_backup, 3673 'My appended text for lambda\n') 3674 svntest.main.file_append(mu_path_backup, 3675 'My appended text for mu\n') 3676 svntest.main.file_append(alpha_path_backup, 3677 'My appended text for alpha\n') 3678 svntest.main.file_append(beta_path_backup, 3679 'My appended text for beta\n') 3680 svntest.main.file_append(p_i_path_backup, 3681 'My appended text for pi\n') 3682 svntest.main.file_append(rho_path_backup, 3683 'My appended text for rho\n') 3684 3685 # Created expected output tree for 'svn ci' 3686 expected_output = svntest.wc.State(wc_dir, { 3687 'iota' : Item(verb='Sending'), 3688 'A/B/lambda' : Item(verb='Sending'), 3689 'A/mu' : Item(verb='Sending'), 3690 'A/B/E/alpha': Item(verb='Sending'), 3691 'A/B/E/beta': Item(verb='Sending'), 3692 'A/D/G/p; i' : Item(verb='Sending'), 3693 'A/D/G/rho' : Item(verb='Sending'), 3694 }) 3695 3696 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 3697 expected_status.tweak('iota', wc_rev=3) 3698 expected_status.tweak('A/B/lambda', wc_rev=3) 3699 expected_status.tweak('A/mu', wc_rev=3) 3700 expected_status.tweak('A/B/E/alpha', wc_rev=3) 3701 expected_status.tweak('A/B/E/beta', wc_rev=3) 3702 expected_status.rename({'A/D/G/pi': 'A/D/G/p; i'}) 3703 expected_status.tweak('A/D/G/p; i', wc_rev=3) 3704 expected_status.tweak('A/D/G/rho', wc_rev=3) 3705 3706 # Commit. 3707 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 3708 expected_status) 3709 3710 # Now we'll update each of our 5 files in wc_backup; each one will get 3711 # conflicts, and we'll handle each with a different --accept option. 3712 3713 # Setup SVN_EDITOR and SVN_MERGE for --accept={edit,launch}. 3714 svntest.main.use_editor('append_foo') 3715 3716 # iota: no accept option 3717 # Just leave the conflicts alone, since run_and_verify_svn already uses 3718 # the --non-interactive option. 3719 svntest.actions.run_and_verify_svn(update_output_with_conflicts( 3720 3, iota_path_backup), 3721 [], 3722 'update', iota_path_backup) 3723 3724 # lambda: --accept=postpone 3725 # Just leave the conflicts alone. 3726 svntest.actions.run_and_verify_svn(update_output_with_conflicts( 3727 3, lambda_path_backup), 3728 [], 3729 'update', '--accept=postpone', 3730 lambda_path_backup) 3731 3732 # mu: --accept=base 3733 # Accept the pre-update base file. 3734 svntest.actions.run_and_verify_svn(update_output_with_conflicts_resolved( 3735 3, mu_path_backup), 3736 [], 3737 'update', '--accept=base', 3738 mu_path_backup) 3739 3740 # alpha: --accept=mine 3741 # Accept the user's working file. 3742 svntest.actions.run_and_verify_svn(update_output_with_conflicts_resolved( 3743 3, alpha_path_backup), 3744 [], 3745 'update', '--accept=mine-full', 3746 alpha_path_backup) 3747 3748 # beta: --accept=theirs 3749 # Accept their file. 3750 svntest.actions.run_and_verify_svn(update_output_with_conflicts_resolved( 3751 3, beta_path_backup), 3752 [], 3753 'update', '--accept=theirs-full', 3754 beta_path_backup) 3755 3756 # pi: --accept=edit 3757 # Run editor and accept the edited file. The merge tool will leave 3758 # conflicts in place, so expect a message on stderr, but expect 3759 # svn to exit with an exit code of 0. 3760 svntest.actions.run_and_verify_svn2(update_output_with_conflicts_resolved( 3761 3, p_i_path_backup), 3762 "system(.*) returned.*", 0, 3763 'update', '--accept=edit', 3764 '--force-interactive', 3765 p_i_path_backup) 3766 3767 # rho: --accept=launch 3768 # Run the external merge tool, it should leave conflict markers in place. 3769 svntest.actions.run_and_verify_svn(update_output_with_conflicts( 3770 3, rho_path_backup), 3771 [], 3772 'update', '--accept=launch', 3773 '--force-interactive', 3774 rho_path_backup) 3775 3776 # Set the expected disk contents for the test 3777 expected_disk = svntest.main.greek_state.copy() 3778 3779 expected_disk.tweak('iota', contents=("This is the file 'iota'.\n" 3780 '<<<<<<< .mine\n' 3781 'My appended text for iota\n' 3782 '||||||| .r2\n' 3783 '=======\n' 3784 'Their appended text for iota\n' 3785 '>>>>>>> .r3\n')) 3786 expected_disk.tweak('A/B/lambda', contents=("This is the file 'lambda'.\n" 3787 '<<<<<<< .mine\n' 3788 'My appended text for lambda\n' 3789 '||||||| .r2\n' 3790 '=======\n' 3791 'Their appended text for lambda\n' 3792 '>>>>>>> .r3\n')) 3793 expected_disk.tweak('A/mu', contents="This is the file 'mu'.\n") 3794 expected_disk.tweak('A/B/E/alpha', contents=("This is the file 'alpha'.\n" 3795 'My appended text for alpha\n')) 3796 expected_disk.tweak('A/B/E/beta', contents=("This is the file 'beta'.\n" 3797 'Their appended text for beta\n')) 3798 expected_disk.rename({'A/D/G/pi': 'A/D/G/p; i'}) 3799 expected_disk.tweak('A/D/G/p; i', contents=("This is the file 'pi'.\n" 3800 '<<<<<<< .mine\n' 3801 'My appended text for pi\n' 3802 '||||||| .r2\n' 3803 '=======\n' 3804 'Their appended text for pi\n' 3805 '>>>>>>> .r3\n' 3806 'foo\n')) 3807 expected_disk.tweak('A/D/G/rho', contents=("This is the file 'rho'.\n" 3808 '<<<<<<< .mine\n' 3809 'My appended text for rho\n' 3810 '||||||| .r2\n' 3811 '=======\n' 3812 'Their appended text for rho\n' 3813 '>>>>>>> .r3\n' 3814 'foo\n')) 3815 3816 # Set the expected extra files for the test 3817 extra_files = ['iota.*\.r2', 'iota.*\.r3', 'iota.*\.mine', 3818 'lambda.*\.r2', 'lambda.*\.r3', 'lambda.*\.mine', 3819 'rho.*\.r2', 'rho.*\.r3', 'rho.*\.mine'] 3820 3821 # Set the expected status for the test 3822 expected_status = svntest.actions.get_virginal_state(wc_backup, 3) 3823 expected_status.rename({'A/D/G/pi': 'A/D/G/p; i'}) 3824 expected_status.tweak('iota', 'A/B/lambda', 'A/mu', 3825 'A/B/E/alpha', 'A/B/E/beta', 3826 'A/D/G/p; i', 'A/D/G/rho', wc_rev=3) 3827 expected_status.tweak('iota', status='C ') 3828 expected_status.tweak('A/B/lambda', status='C ') 3829 expected_status.tweak('A/mu', status='M ') 3830 expected_status.tweak('A/B/E/alpha', status='M ') 3831 expected_status.tweak('A/B/E/beta', status=' ') 3832 expected_status.tweak('A/D/G/p; i', status='M ') 3833 expected_status.tweak('A/D/G/rho', status='C ') 3834 3835 # Set the expected output for the test 3836 expected_output = wc.State(wc_backup, {}) 3837 3838 # Do the update and check the results in three ways. 3839 svntest.actions.run_and_verify_update(wc_backup, 3840 expected_output, 3841 expected_disk, 3842 expected_status, 3843 extra_files=extra_files) 3844 3845 3846#---------------------------------------------------------------------- 3847 3848 3849def update_uuid_changed(sbox): 3850 "update fails when repos uuid changed" 3851 3852 # read_only=False, since we don't want to run setuuid on the (shared) 3853 # pristine repository. 3854 sbox.build(read_only = False) 3855 3856 wc_dir = sbox.wc_dir 3857 repo_dir = sbox.repo_dir 3858 3859 uuid_before = svntest.actions.get_wc_uuid(wc_dir) 3860 3861 # Change repository's uuid. 3862 svntest.actions.run_and_verify_svnadmin(None, [], 3863 'setuuid', repo_dir) 3864 3865 # 'update' detected the new uuid... 3866 svntest.actions.run_and_verify_svn(None, '.*UUID.*', 3867 'update', wc_dir) 3868 3869 # ...and didn't overwrite the old uuid. 3870 uuid_after = svntest.actions.get_wc_uuid(wc_dir) 3871 if uuid_before != uuid_after: 3872 raise svntest.Failure 3873 3874 3875#---------------------------------------------------------------------- 3876 3877# Issue #1672: if an update deleting a dir prop is interrupted (by a 3878# local obstruction, for example) then restarting the update will not 3879# delete the prop, causing the wc to become out of sync with the 3880# repository. 3881def restarted_update_should_delete_dir_prop(sbox): 3882 "restarted update should delete dir prop" 3883 sbox.build() 3884 wc_dir = sbox.wc_dir 3885 3886 A_path = sbox.ospath('A') 3887 zeta_path = os.path.join(A_path, 'zeta') 3888 3889 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 3890 3891 # Commit a propset on A. 3892 svntest.main.run_svn(None, 'propset', 'prop', 'val', A_path) 3893 3894 expected_output = svntest.wc.State(wc_dir, { 3895 'A': Item(verb='Sending'), 3896 }) 3897 3898 expected_status.tweak('A', wc_rev=2) 3899 3900 svntest.actions.run_and_verify_commit(wc_dir, expected_output, 3901 expected_status) 3902 3903 # Create a second working copy. 3904 ### Does this hack still work with wc-ng? 3905 other_wc = sbox.add_wc_path('other') 3906 svntest.actions.duplicate_dir(wc_dir, other_wc) 3907 3908 other_A_path = os.path.join(other_wc, 'A') 3909 other_zeta_path = os.path.join(other_wc, 'A', 'zeta') 3910 3911 # In the second working copy, delete A's prop and add a new file. 3912 svntest.main.run_svn(None, 'propdel', 'prop', other_A_path) 3913 svntest.main.file_write(other_zeta_path, 'New file\n') 3914 svntest.main.run_svn(None, 'add', other_zeta_path) 3915 3916 expected_output = svntest.wc.State(other_wc, { 3917 'A': Item(verb='Sending'), 3918 'A/zeta' : Item(verb='Adding'), 3919 }) 3920 3921 expected_status = svntest.actions.get_virginal_state(other_wc, 1) 3922 expected_status.tweak('A', wc_rev=3) 3923 expected_status.add({ 3924 'A/zeta' : Item(status=' ', wc_rev=3), 3925 }) 3926 3927 svntest.actions.run_and_verify_commit(other_wc, expected_output, 3928 expected_status) 3929 3930 # Back in the first working copy, create an obstructing path and 3931 # update. The update will flag a tree conflict. 3932 svntest.main.file_write(zeta_path, 'Obstructing file\n') 3933 3934 #svntest.factory.make(sbox, 'svn up') 3935 #exit(0) 3936 # svn up 3937 expected_output = svntest.wc.State(wc_dir, { 3938 'A' : Item(status=' U'), 3939 'A/zeta' : Item(status=' ', treeconflict='C'), 3940 }) 3941 3942 expected_disk = svntest.main.greek_state.copy() 3943 expected_disk.add({ 3944 'A/zeta' : Item(contents="Obstructing file\n"), 3945 }) 3946 3947 expected_status = actions.get_virginal_state(wc_dir, 3) 3948 expected_status.add({ 3949 'A/zeta' : Item(status='D ', treeconflict='C', wc_rev='3'), 3950 }) 3951 3952 actions.run_and_verify_update(wc_dir, expected_output, expected_disk, 3953 expected_status) 3954 3955 # Now, delete the obstructing path and rerun the update. 3956 os.unlink(zeta_path) 3957 3958 svntest.main.run_svn(None, 'revert', zeta_path) 3959 3960 expected_output = svntest.wc.State(wc_dir, { 3961 }) 3962 3963 expected_disk = svntest.main.greek_state.copy() 3964 expected_disk.tweak('A', props = {}) 3965 expected_disk.add({ 3966 'A/zeta' : Item("New file\n"), 3967 }) 3968 3969 expected_status = svntest.actions.get_virginal_state(wc_dir, 3) 3970 expected_status.add({ 3971 'A/zeta' : Item(status=' ', wc_rev=3), 3972 }) 3973 3974 svntest.actions.run_and_verify_update(wc_dir, 3975 expected_output, 3976 expected_disk, 3977 expected_status, 3978 check_props = True) 3979 3980#---------------------------------------------------------------------- 3981 3982# Detect tree conflicts among files and directories, 3983# edited or deleted in a deep directory structure. 3984# 3985# See use cases 1-3 in notes/tree-conflicts/use-cases.txt for background. 3986 3987# convenience definitions 3988leaf_edit = svntest.deeptrees.deep_trees_leaf_edit 3989tree_del = svntest.deeptrees.deep_trees_tree_del 3990leaf_del = svntest.deeptrees.deep_trees_leaf_del 3991 3992disk_after_leaf_edit = svntest.deeptrees.deep_trees_after_leaf_edit 3993disk_after_leaf_del = svntest.deeptrees.deep_trees_after_leaf_del 3994disk_after_tree_del = svntest.deeptrees.deep_trees_after_tree_del 3995 3996deep_trees_conflict_output = svntest.deeptrees.deep_trees_conflict_output 3997deep_trees_conflict_output_skipped = \ 3998 svntest.deeptrees.deep_trees_conflict_output_skipped 3999deep_trees_status_local_tree_del = \ 4000 svntest.deeptrees.deep_trees_status_local_tree_del 4001deep_trees_status_local_leaf_edit = \ 4002 svntest.deeptrees.deep_trees_status_local_leaf_edit 4003 4004DeepTreesTestCase = svntest.deeptrees.DeepTreesTestCase 4005 4006 4007def tree_conflicts_on_update_1_1(sbox): 4008 "tree conflicts 1.1: tree del, leaf edit on update" 4009 4010 # use case 1, as in notes/tree-conflicts/use-cases.txt 4011 # 1.1) local tree delete, incoming leaf edit 4012 4013 sbox.build() 4014 4015 expected_output = deep_trees_conflict_output.copy() 4016 expected_output.add({ 4017 'DDF/D1/D2' : Item(status=' ', treeconflict='U'), 4018 'DDF/D1/D2/gamma' : Item(status=' ', treeconflict='U'), 4019 'DD/D1/D2' : Item(status=' ', treeconflict='U'), 4020 'DD/D1/D2/epsilon' : Item(status=' ', treeconflict='A'), 4021 'DDD/D1/D2' : Item(status=' ', treeconflict='U'), 4022 'DDD/D1/D2/D3' : Item(status=' ', treeconflict='U'), 4023 'DDD/D1/D2/D3/zeta' : Item(status=' ', treeconflict='A'), 4024 'D/D1/delta' : Item(status=' ', treeconflict='A'), 4025 'DF/D1/beta' : Item(status=' ', treeconflict='U'), 4026 }) 4027 4028 expected_disk = svntest.wc.State('', { 4029 'F' : Item(), 4030 'D' : Item(), 4031 'DF' : Item(), 4032 'DD' : Item(), 4033 'DDF' : Item(), 4034 'DDD' : Item(), 4035 }) 4036 # The files delta, epsilon, and zeta are incoming additions, but since 4037 # they are all within locally deleted trees they should also be schedule 4038 # for deletion. 4039 expected_status = deep_trees_status_local_tree_del.copy() 4040 expected_status.add({ 4041 'D/D1/delta' : Item(status='D '), 4042 'DD/D1/D2/epsilon' : Item(status='D '), 4043 'DDD/D1/D2/D3/zeta' : Item(status='D '), 4044 }) 4045 4046 # Update to the target rev. 4047 expected_status.tweak(wc_rev=3) 4048 4049 expected_info = { 4050 'F/alpha' : { 4051 'Tree conflict' : 4052 '^local file delete, incoming file edit upon update' 4053 + ' Source left: .file.*/F/alpha@2' 4054 + ' Source right: .file.*/F/alpha@3$', 4055 }, 4056 'DF/D1' : { 4057 'Tree conflict' : 4058 '^local dir delete, incoming dir edit upon update' 4059 + ' Source left: .dir.*/DF/D1@2' 4060 + ' Source right: .dir.*/DF/D1@3$', 4061 }, 4062 'DDF/D1' : { 4063 'Tree conflict' : 4064 '^local dir delete, incoming dir edit upon update' 4065 + ' Source left: .dir.*/DDF/D1@2' 4066 + ' Source right: .dir.*/DDF/D1@3$', 4067 }, 4068 'D/D1' : { 4069 'Tree conflict' : 4070 '^local dir delete, incoming dir edit upon update' 4071 + ' Source left: .dir.*/D/D1@2' 4072 + ' Source right: .dir.*/D/D1@3$', 4073 }, 4074 'DD/D1' : { 4075 'Tree conflict' : 4076 '^local dir delete, incoming dir edit upon update' 4077 + ' Source left: .dir.*/DD/D1@2' 4078 + ' Source right: .dir.*/DD/D1@3$', 4079 }, 4080 'DDD/D1' : { 4081 'Tree conflict' : 4082 '^local dir delete, incoming dir edit upon update' 4083 + ' Source left: .dir.*/DDD/D1@2' 4084 + ' Source right: .dir.*/DDD/D1@3$', 4085 }, 4086 } 4087 4088 svntest.deeptrees.deep_trees_run_tests_scheme_for_update(sbox, 4089 [ DeepTreesTestCase("local_tree_del_incoming_leaf_edit", 4090 tree_del, 4091 leaf_edit, 4092 expected_output, 4093 expected_disk, 4094 expected_status, 4095 expected_info = expected_info) ] ) 4096 4097 4098def tree_conflicts_on_update_1_2(sbox): 4099 "tree conflicts 1.2: tree del, leaf del on update" 4100 4101 # 1.2) local tree delete, incoming leaf delete 4102 4103 sbox.build() 4104 4105 expected_output = deep_trees_conflict_output.copy() 4106 expected_output.add({ 4107 'DDD/D1/D2' : Item(status=' ', treeconflict='U'), 4108 'DDD/D1/D2/D3' : Item(status=' ', treeconflict='D'), 4109 'DF/D1/beta' : Item(status=' ', treeconflict='D'), 4110 'DD/D1/D2' : Item(status=' ', treeconflict='D'), 4111 'DDF/D1/D2' : Item(status=' ', treeconflict='U'), 4112 'DDF/D1/D2/gamma' : Item(status=' ', treeconflict='D'), 4113 }) 4114 4115 expected_disk = svntest.wc.State('', { 4116 'F' : Item(), 4117 'D' : Item(), 4118 'DF' : Item(), 4119 'DD' : Item(), 4120 'DDF' : Item(), 4121 'DDD' : Item(), 4122 }) 4123 4124 expected_status = deep_trees_status_local_tree_del.copy() 4125 4126 # Expect the incoming leaf deletes to actually occur. Even though they 4127 # are within (or in the case of F/alpha and D/D1 are the same as) the 4128 # trees locally scheduled for deletion we must still delete them and 4129 # update the scheduled for deletion items to the target rev. Otherwise 4130 # once the conflicts are resolved we still have a mixed-rev WC we can't 4131 # commit without updating...which, you guessed it, raises tree conflicts 4132 # again, repeat ad infinitum - see issue #3334. 4133 # 4134 # Update to the target rev. 4135 expected_status.tweak(wc_rev=3) 4136 expected_status.tweak('F/alpha', 4137 'D/D1', 4138 status='! ', wc_rev=None) 4139 # Remove the incoming deletes from status and disk. 4140 expected_status.remove('DD/D1/D2', 4141 'DDD/D1/D2/D3', 4142 'DDF/D1/D2/gamma', 4143 'DF/D1/beta') 4144 4145 expected_info = { 4146 'F/alpha' : { 4147 'Tree conflict' : 4148 '^local file delete, incoming file delete or move upon update' 4149 + ' Source left: .file.*/F/alpha@2' 4150 + ' Source right: .none.*(/F/alpha@3)?$', 4151 }, 4152 'DF/D1' : { 4153 'Tree conflict' : 4154 '^local dir delete, incoming dir edit upon update' 4155 + ' Source left: .dir.*/DF/D1@2' 4156 + ' Source right: .dir.*/DF/D1@3$', 4157 }, 4158 'DDF/D1' : { 4159 'Tree conflict' : 4160 '^local dir delete, incoming dir edit upon update' 4161 + ' Source left: .dir.*/DDF/D1@2' 4162 + ' Source right: .dir.*/DDF/D1@3$', 4163 }, 4164 'D/D1' : { 4165 'Tree conflict' : 4166 '^local dir delete, incoming dir delete or move upon update' 4167 + ' Source left: .dir.*/D/D1@2' 4168 + ' Source right: .none.*(/D/D1@3)?$', 4169 }, 4170 'DD/D1' : { 4171 'Tree conflict' : 4172 '^local dir delete, incoming dir edit upon update' 4173 + ' Source left: .dir.*/DD/D1@2' 4174 + ' Source right: .dir.*/DD/D1@3$', 4175 }, 4176 'DDD/D1' : { 4177 'Tree conflict' : 4178 '^local dir delete, incoming dir edit upon update' 4179 + ' Source left: .dir.*/DDD/D1@2' 4180 + ' Source right: .dir.*/DDD/D1@3$', 4181 }, 4182 } 4183 4184 svntest.deeptrees.deep_trees_run_tests_scheme_for_update(sbox, 4185 [ DeepTreesTestCase("local_tree_del_incoming_leaf_del", 4186 tree_del, 4187 leaf_del, 4188 expected_output, 4189 expected_disk, 4190 expected_status, 4191 expected_info = expected_info) ] ) 4192 4193 4194def tree_conflicts_on_update_2_1(sbox): 4195 "tree conflicts 2.1: leaf edit, tree del on update" 4196 4197 # use case 2, as in notes/tree-conflicts/use-cases.txt 4198 # 2.1) local leaf edit, incoming tree delete 4199 4200 expected_output = deep_trees_conflict_output 4201 4202 expected_disk = disk_after_leaf_edit 4203 4204 expected_status = deep_trees_status_local_leaf_edit.copy() 4205 # Adjust the status of the roots of the six subtrees scheduled for deletion 4206 # during the update. Since these are all tree conflicts, they will all be 4207 # scheduled for addition as copies with history - see Issue #3334. 4208 expected_status.tweak( 4209 'D/D1', 4210 'F/alpha', 4211 'DD/D1', 4212 'DF/D1', 4213 'DDD/D1', 4214 'DDF/D1', 4215 status='A ', copied='+', wc_rev='-') 4216 # See the status of all the paths *under* the above six subtrees. Only the 4217 # roots of the added subtrees show as schedule 'A', these childs paths show 4218 # only that history is scheduled with the commit. 4219 expected_status.tweak( 4220 'DD/D1/D2', 4221 'DDD/D1/D2', 4222 'DDD/D1/D2/D3', 4223 'DF/D1/beta', 4224 'DDF/D1/D2', 4225 'DDF/D1/D2/gamma', 4226 copied='+', wc_rev='-') 4227 4228 expected_info = { 4229 'F/alpha' : { 4230 'Tree conflict' : 4231 '^local file edit, incoming file delete or move upon update' 4232 + ' Source left: .file.*/F/alpha@2' 4233 + ' Source right: .none.*(/F/alpha@3)?$', 4234 }, 4235 'DF/D1' : { 4236 'Tree conflict' : 4237 '^local dir edit, incoming dir delete or move upon update' 4238 + ' Source left: .dir.*/DF/D1@2' 4239 + ' Source right: .none.*(/DF/D1@3)?$', 4240 }, 4241 'DDF/D1' : { 4242 'Tree conflict' : 4243 '^local dir edit, incoming dir delete or move upon update' 4244 + ' Source left: .dir.*/DDF/D1@2' 4245 + ' Source right: .none.*(/DDF/D1@3)?$', 4246 }, 4247 'D/D1' : { 4248 'Tree conflict' : 4249 '^local dir edit, incoming dir delete or move upon update' 4250 + ' Source left: .dir.*/D/D1@2' 4251 + ' Source right: .none.*(/D/D1@3)?$', 4252 }, 4253 'DD/D1' : { 4254 'Tree conflict' : 4255 '^local dir edit, incoming dir delete or move upon update' 4256 + ' Source left: .dir.*/DD/D1@2' 4257 + ' Source right: .none.*(/DD/D1@3)?$', 4258 }, 4259 'DDD/D1' : { 4260 'Tree conflict' : 4261 '^local dir edit, incoming dir delete or move upon update' 4262 + ' Source left: .dir.*/DDD/D1@2' 4263 + ' Source right: .none.*(/DDD/D1@3)?$', 4264 }, 4265 } 4266 4267 ### D/D1/delta is locally-added during leaf_edit. when tree_del executes, 4268 ### it will delete D/D1, and the update reschedules local D/D1 for 4269 ### local-copy from its original revision. however, right now, we cannot 4270 ### denote that delta is a local-add rather than a child of that D/D1 copy. 4271 ### thus, it appears in the status output as a (M)odified child. 4272 svntest.deeptrees.deep_trees_run_tests_scheme_for_update(sbox, 4273 [ DeepTreesTestCase("local_leaf_edit_incoming_tree_del", 4274 leaf_edit, 4275 tree_del, 4276 expected_output, 4277 expected_disk, 4278 expected_status, 4279 expected_info = expected_info) ] ) 4280 4281 4282 4283def tree_conflicts_on_update_2_2(sbox): 4284 "tree conflicts 2.2: leaf del, tree del on update" 4285 4286 # 2.2) local leaf delete, incoming tree delete 4287 4288 ### Current behaviour fails to show conflicts when deleting 4289 ### a directory tree that has modifications. (Will be solved 4290 ### when dirs_same_p() is implemented) 4291 expected_output = deep_trees_conflict_output 4292 4293 expected_disk = svntest.wc.State('', { 4294 'DDF/D1/D2' : Item(), 4295 'F' : Item(), 4296 'D' : Item(), 4297 'DF/D1' : Item(), 4298 'DD/D1' : Item(), 4299 'DDD/D1/D2' : Item(), 4300 }) 4301 4302 expected_status = svntest.deeptrees.deep_trees_virginal_state.copy() 4303 expected_status.add({'' : Item()}) 4304 expected_status.tweak(contents=None, status=' ', wc_rev=3) 4305 # Tree conflicts. 4306 expected_status.tweak( 4307 'D/D1', 4308 'F/alpha', 4309 'DD/D1', 4310 'DF/D1', 4311 'DDD/D1', 4312 'DDF/D1', 4313 treeconflict='C', wc_rev=2) 4314 4315 # Expect the incoming tree deletes and the local leaf deletes to mean 4316 # that all deleted paths are *really* gone, not simply scheduled for 4317 # deletion. 4318 expected_status.tweak('DD/D1', 'DF/D1', 'DDF/D1', 'DDD/D1', 4319 status='A ', copied='+', treeconflict='C', 4320 wc_rev='-') 4321 expected_status.tweak('DDF/D1/D2', 'DDD/D1/D2', 4322 copied='+', wc_rev='-') 4323 expected_status.tweak('DD/D1/D2', 'DF/D1/beta', 'DDD/D1/D2/D3', 4324 'DDF/D1/D2/gamma', 4325 status='D ', copied='+', wc_rev='-') 4326 expected_status.tweak('F/alpha', 'D/D1', 4327 status='! ', treeconflict='C', wc_rev=None) 4328 4329 expected_info = { 4330 'F/alpha' : { 4331 'Tree conflict' : 4332 '^local file delete, incoming file delete or move upon update' 4333 + ' Source left: .file.*/F/alpha@2' 4334 + ' Source right: .none.*(/F/alpha@3)?$', 4335 }, 4336 'DF/D1' : { 4337 'Tree conflict' : 4338 '^local dir edit, incoming dir delete or move upon update' 4339 + ' Source left: .dir.*/DF/D1@2' 4340 + ' Source right: .none.*(/DF/D1@3)?$', 4341 }, 4342 'DDF/D1' : { 4343 'Tree conflict' : 4344 '^local dir edit, incoming dir delete or move upon update' 4345 + ' Source left: .dir.*/DDF/D1@2' 4346 + ' Source right: .none.*(/DDF/D1@3)?$', 4347 }, 4348 'D/D1' : { 4349 'Tree conflict' : 4350 '^local dir delete, incoming dir delete or move upon update' 4351 + ' Source left: .dir.*/D/D1@2' 4352 + ' Source right: .none.*(/D/D1@3)?$', 4353 }, 4354 'DD/D1' : { 4355 'Tree conflict' : 4356 '^local dir edit, incoming dir delete or move upon update' 4357 + ' Source left: .dir.*/DD/D1@2' 4358 + ' Source right: .none.*(/DD/D1@3)?$', 4359 }, 4360 'DDD/D1' : { 4361 'Tree conflict' : 4362 '^local dir edit, incoming dir delete or move upon update' 4363 + ' Source left: .dir.*/DDD/D1@2' 4364 + ' Source right: .none.*(/DDD/D1@3)?$', 4365 }, 4366 } 4367 4368 svntest.deeptrees.deep_trees_run_tests_scheme_for_update(sbox, 4369 [ DeepTreesTestCase("local_leaf_del_incoming_tree_del", 4370 leaf_del, 4371 tree_del, 4372 expected_output, 4373 expected_disk, 4374 expected_status, 4375 expected_info = expected_info) ] ) 4376 4377 4378#---------------------------------------------------------------------- 4379# Test for issue #3329 'Update throws error when skipping some tree 4380# conflicts' 4381# 4382# Marked as XFail until issue #3329 is resolved. 4383@Issue(3329) 4384def tree_conflicts_on_update_2_3(sbox): 4385 "tree conflicts 2.3: skip on 2nd update" 4386 4387 # Test that existing tree conflicts are skipped 4388 4389 expected_output = deep_trees_conflict_output_skipped 4390 4391 expected_disk = disk_after_leaf_edit 4392 4393 expected_status = deep_trees_status_local_leaf_edit.copy() 4394 4395 # Adjust the status of the roots of the six subtrees scheduled for deletion 4396 # during the update. Since these are all tree conflicts, they will all be 4397 # scheduled for addition as copies with history - see Issue #3334. 4398 expected_status.tweak( 4399 'D/D1', 4400 'F/alpha', 4401 'DD/D1', 4402 'DF/D1', 4403 'DDD/D1', 4404 'DDF/D1', 4405 status='A ', copied='+', wc_rev='-') 4406 # See the status of all the paths *under* the above six subtrees. Only the 4407 # roots of the added subtrees show as schedule 'A', these child paths show 4408 # only that history is scheduled with the commit. 4409 expected_status.tweak( 4410 'DD/D1/D2', 4411 'DDD/D1/D2', 4412 'DDD/D1/D2/D3', 4413 'DF/D1/beta', 4414 'DDF/D1/D2', 4415 'DDF/D1/D2/gamma', 4416 copied='+', wc_rev='-') 4417 4418 # Paths where output should be a single 'Skipped' message. 4419 skip_paths = [ 4420 'D/D1', 4421 'F/alpha', 4422 'DDD/D1', 4423 'DDD/D1/D2/D3', 4424 ] 4425 4426 # This is where the test fails. Repeat updates on '', 'D', 'F', or 4427 # 'DDD' report no skips. 4428 chdir_skip_paths = [ 4429 ('D', 'D1'), 4430 ('F', 'alpha'), 4431 ('DDD', 'D1'), 4432 ('', ['D/D1', 'F/alpha', 'DD/D1', 'DF/D1', 'DDD/D1', 'DDF/D1']), 4433 ] 4434 # Note: We don't step *into* a directory that's deleted in the repository. 4435 # E.g. ('DDD/D1/D2', '') would correctly issue a "path does not 4436 # exist" error, because at that point it can't know about the 4437 # tree-conflict on DDD/D1. ('D/D1', '') likewise, as tree-conflict 4438 # information is stored in the parent of a victim directory. 4439 4440 svntest.deeptrees.deep_trees_skipping_on_update(sbox, 4441 DeepTreesTestCase("local_leaf_edit_incoming_tree_del_skipping", 4442 leaf_edit, 4443 tree_del, 4444 expected_output, 4445 expected_disk, 4446 expected_status), 4447 skip_paths, 4448 chdir_skip_paths) 4449 4450 4451def tree_conflicts_on_update_3(sbox): 4452 "tree conflicts 3: tree del, tree del on update" 4453 4454 # use case 3, as in notes/tree-conflicts/use-cases.txt 4455 # local tree delete, incoming tree delete 4456 4457 expected_output = deep_trees_conflict_output 4458 4459 expected_disk = svntest.wc.State('', { 4460 'F' : Item(), 4461 'D' : Item(), 4462 'DF' : Item(), 4463 'DD' : Item(), 4464 'DDF' : Item(), 4465 'DDD' : Item(), 4466 }) 4467 expected_status = deep_trees_status_local_tree_del.copy() 4468 4469 # Expect the incoming tree deletes and the local tree deletes to mean 4470 # that all deleted paths are *really* gone, not simply scheduled for 4471 # deletion. 4472 expected_status.tweak('F/alpha', 4473 'D/D1', 4474 'DD/D1', 4475 'DF/D1', 4476 'DDD/D1', 4477 'DDF/D1', 4478 status='! ', wc_rev=None) 4479 # Remove from expected status and disk everything below the deleted paths. 4480 expected_status.remove('DD/D1/D2', 4481 'DF/D1/beta', 4482 'DDD/D1/D2', 4483 'DDD/D1/D2/D3', 4484 'DDF/D1/D2', 4485 'DDF/D1/D2/gamma',) 4486 4487 expected_info = { 4488 'F/alpha' : { 4489 'Tree conflict' : 4490 '^local file delete, incoming file delete or move upon update' 4491 + ' Source left: .file.*/F/alpha@2' 4492 + ' Source right: .none.*(/F/alpha@3)?$', 4493 }, 4494 'DF/D1' : { 4495 'Tree conflict' : 4496 '^local dir delete, incoming dir delete or move upon update' 4497 + ' Source left: .dir.*/DF/D1@2' 4498 + ' Source right: .none.*(/DF/D1@3)?$', 4499 }, 4500 'DDF/D1' : { 4501 'Tree conflict' : 4502 '^local dir delete, incoming dir delete or move upon update' 4503 + ' Source left: .dir.*/DDF/D1@2' 4504 + ' Source right: .none.*(/DDF/D1@3)?$', 4505 }, 4506 'D/D1' : { 4507 'Tree conflict' : 4508 '^local dir delete, incoming dir delete or move upon update' 4509 + ' Source left: .dir.*/D/D1@2' 4510 + ' Source right: .none.*(/D/D1@3)?$', 4511 }, 4512 'DD/D1' : { 4513 'Tree conflict' : 4514 '^local dir delete, incoming dir delete or move upon update' 4515 + ' Source left: .dir.*/DD/D1@2' 4516 + ' Source right: .none.*(/DD/D1@3)?$', 4517 }, 4518 'DDD/D1' : { 4519 'Tree conflict' : 4520 '^local dir delete, incoming dir delete or move upon update' 4521 + ' Source left: .dir.*/DDD/D1@2' 4522 + ' Source right: .none.*(/DDD/D1@3)?$', 4523 }, 4524 } 4525 4526 svntest.deeptrees.deep_trees_run_tests_scheme_for_update(sbox, 4527 [ DeepTreesTestCase("local_tree_del_incoming_tree_del", 4528 tree_del, 4529 tree_del, 4530 expected_output, 4531 expected_disk, 4532 expected_status, 4533 expected_info = expected_info) ] ) 4534 4535# Issue #3334: a modify-on-deleted tree conflict should leave the node 4536# updated to the target revision but still scheduled for deletion. 4537def tree_conflict_uc1_update_deleted_tree(sbox): 4538 "tree conflicts on update UC1, update deleted tree" 4539 sbox.build() 4540 wc_dir = sbox.wc_dir 4541 4542 from svntest.actions import run_and_verify_svn, run_and_verify_resolve 4543 from svntest.actions import run_and_verify_update, run_and_verify_commit 4544 from svntest.verify import AnyOutput 4545 4546 """A directory tree 'D1' should end up exactly the same in these two 4547 scenarios: 4548 4549 New scenario: 4550 [[[ 4551 svn checkout -r1 # in which D1 has its original state 4552 svn delete D1 4553 svn update -r2 # update revs & bases to r2 4554 svn resolve --accept=mine # keep the local, deleted version 4555 ]]] 4556 4557 Existing scenario: 4558 [[[ 4559 svn checkout -r2 # in which D1 is already modified 4560 svn delete D1 4561 ]]] 4562 """ 4563 4564 A = sbox.ospath('A') 4565 4566 def modify_dir(dir): 4567 """Make some set of local modifications to an existing tree: 4568 A prop change, add a child, delete a child, change a child.""" 4569 run_and_verify_svn(AnyOutput, [], 'propset', 'p', 'v', dir) 4570 4571 path = os.path.join(dir, 'new_file') 4572 svntest.main.file_write(path, "This is the file 'new_file'.\n") 4573 svntest.actions.run_and_verify_svn(None, [], 'add', path) 4574 4575 path = os.path.join(dir, 'C', 'N') 4576 os.mkdir(path) 4577 path2 = os.path.join(dir, 'C', 'N', 'nu') 4578 svntest.main.file_write(path2, "This is the file 'nu'.\n") 4579 svntest.actions.run_and_verify_svn(None, [], 'add', path) 4580 4581 path = os.path.join(dir, 'B', 'lambda') 4582 svntest.actions.run_and_verify_svn(None, [], 'delete', path) 4583 4584 path = os.path.join(dir, 'B', 'E', 'alpha') 4585 svntest.main.file_append(path, "An extra line.\n") 4586 4587 # Prep for both scenarios 4588 modify_dir(A) 4589 run_and_verify_svn(AnyOutput, [], 'ci', A, '-m', 'modify_dir') 4590 run_and_verify_svn(AnyOutput, [], 'up', wc_dir) 4591 4592 # Existing scenario 4593 wc2 = sbox.add_wc_path('wc2') 4594 A2 = os.path.join(wc2, 'A') 4595 svntest.actions.duplicate_dir(sbox.wc_dir, wc2) 4596 run_and_verify_svn(AnyOutput, [], 'delete', A2) 4597 4598 # New scenario (starts at the revision before the committed mods) 4599 run_and_verify_svn(AnyOutput, [], 'up', A, '-r1') 4600 run_and_verify_svn(AnyOutput, [], 'delete', A) 4601 4602 expected_output = None 4603 expected_disk = None 4604 expected_status = None 4605 4606 run_and_verify_update(A, expected_output, expected_disk, expected_status) 4607 run_and_verify_resolve([A], '--recursive', '--accept=working', A) 4608 4609 resolved_status = svntest.wc.State('', { 4610 '' : Item(status=' ', wc_rev=2), 4611 'A' : Item(status='D ', wc_rev=2), 4612 'A/B' : Item(status='D ', wc_rev=2), 4613 'A/B/E' : Item(status='D ', wc_rev=2), 4614 'A/B/E/alpha' : Item(status='D ', wc_rev=2), 4615 'A/B/E/beta' : Item(status='D ', wc_rev=2), 4616 'A/B/F' : Item(status='D ', wc_rev=2), 4617 'A/mu' : Item(status='D ', wc_rev=2), 4618 'A/C' : Item(status='D ', wc_rev=2), 4619 'A/C/N' : Item(status='D ', wc_rev=2), 4620 'A/C/N/nu' : Item(status='D ', wc_rev=2), 4621 'A/D' : Item(status='D ', wc_rev=2), 4622 'A/D/gamma' : Item(status='D ', wc_rev=2), 4623 'A/D/G' : Item(status='D ', wc_rev=2), 4624 'A/D/G/pi' : Item(status='D ', wc_rev=2), 4625 'A/D/G/rho' : Item(status='D ', wc_rev=2), 4626 'A/D/G/tau' : Item(status='D ', wc_rev=2), 4627 'A/D/H' : Item(status='D ', wc_rev=2), 4628 'A/D/H/chi' : Item(status='D ', wc_rev=2), 4629 'A/D/H/omega' : Item(status='D ', wc_rev=2), 4630 'A/D/H/psi' : Item(status='D ', wc_rev=2), 4631 'A/new_file' : Item(status='D ', wc_rev=2), 4632 'iota' : Item(status=' ', wc_rev=2), 4633 }) 4634 4635 # The status of the new and old scenarios should be identical. 4636 expected_status = resolved_status.copy() 4637 expected_status.wc_dir = wc2 4638 4639 svntest.actions.run_and_verify_status(wc2, expected_status) 4640 4641 expected_status = resolved_status.copy() 4642 expected_status.wc_dir = wc_dir 4643 4644 svntest.actions.run_and_verify_status(wc_dir, expected_status) 4645 4646 # Just for kicks, try to commit. 4647 expected_output = svntest.wc.State(wc_dir, { 4648 'A' : Item(verb='Deleting'), 4649 }) 4650 4651 expected_status = svntest.wc.State(wc_dir, { 4652 '' : Item(status=' ', wc_rev=2), 4653 'iota' : Item(status=' ', wc_rev=2), 4654 }) 4655 4656 run_and_verify_commit(wc_dir, expected_output, expected_status, 4657 [], wc_dir, '-m', 'commit resolved tree') 4658 4659 4660# Issue #3334: a delete-onto-modified tree conflict should leave the node 4661# scheduled for re-addition. 4662@Issue(3334) 4663def tree_conflict_uc2_schedule_re_add(sbox): 4664 "tree conflicts on update UC2, schedule re-add" 4665 sbox.build() 4666 saved_cwd = os.getcwd() 4667 os.chdir(sbox.wc_dir) 4668 4669 from svntest.actions import run_and_verify_svn, run_and_verify_resolve 4670 from svntest.actions import run_and_verify_update 4671 from svntest.verify import AnyOutput 4672 4673 """A directory tree 'D1' should end up exactly the same in these two 4674 scenarios: 4675 4676 New scenario: 4677 [[[ 4678 svn checkout -r1 # in which D1 exists 4679 modify_d1 # make local mods in D1 4680 svn update -r2 # tries to delete D1 4681 svn resolve --accept=mine # keep the local, re-added version 4682 ]]] 4683 4684 Existing scenario: 4685 [[[ 4686 svn checkout -r2 # in which D1 does not exist 4687 svn copy -r1 D1 . # make a pristine copy of D1@1 4688 modify_d1 # make local mods in D1 4689 ]]] 4690 4691 where modify_d1 makes property changes to D1 itself and/or 4692 adds/deletes/modifies any of D1's children. 4693 """ 4694 4695 dir = 'A' # an existing tree in the WC and repos 4696 dir_url = sbox.repo_url + '/' + dir 4697 4698 def modify_dir(dir): 4699 """Make some set of local modifications to an existing tree: 4700 A prop change, add a child, delete a child, change a child.""" 4701 run_and_verify_svn(AnyOutput, [], 4702 'propset', 'p', 'v', dir) 4703 path = os.path.join(dir, 'new_file') 4704 svntest.main.file_write(path, "This is the file 'new_file'.\n") 4705 svntest.actions.run_and_verify_svn(None, [], 'add', path) 4706 4707 path = os.path.join(dir, 'B', 'lambda') 4708 svntest.actions.run_and_verify_svn(None, [], 'delete', path) 4709 4710 path = os.path.join(dir, 'B', 'E', 'alpha') 4711 svntest.main.file_append(path, "An extra line.\n") 4712 4713 # Prepare the repos so that a later 'update' has an incoming deletion: 4714 # Delete the dir in the repos, making r2 4715 run_and_verify_svn(AnyOutput, [], 4716 '-m', '', 'delete', dir_url) 4717 4718 # Existing scenario 4719 os.chdir(saved_cwd) 4720 wc2 = sbox.add_wc_path('wc2') 4721 dir2 = os.path.join(wc2, dir) 4722 svntest.actions.duplicate_dir(sbox.wc_dir, wc2) 4723 run_and_verify_svn(AnyOutput, [], 'up', wc2) 4724 run_and_verify_svn(AnyOutput, [], 'copy', dir_url + '@1', dir2) 4725 modify_dir(dir2) 4726 4727 # New scenario 4728 # (The dir is already checked out.) 4729 os.chdir(sbox.wc_dir) 4730 modify_dir(dir) 4731 4732 expected_output = None 4733 expected_disk = None 4734 expected_status = None 4735 run_and_verify_update('A', expected_output, expected_disk, expected_status) 4736 run_and_verify_resolve([dir], '--recursive', '--accept=working', dir) 4737 4738 os.chdir(saved_cwd) 4739 4740 def get_status(dir): 4741 expected_status = svntest.wc.State(dir, { 4742 '' : Item(status=' ', wc_rev='2'), 4743 'A' : Item(status='A ', wc_rev='-', copied='+'), 4744 'A/B' : Item(status=' ', wc_rev='-', copied='+'), 4745 'A/B/lambda' : Item(status='D ', wc_rev='-', copied='+'), 4746 'A/B/E' : Item(status=' ', wc_rev='-', copied='+'), 4747 'A/B/E/alpha' : Item(status='M ', wc_rev='-', copied='+'), 4748 'A/B/E/beta' : Item(status=' ', wc_rev='-', copied='+'), 4749 'A/B/F' : Item(status=' ', wc_rev='-', copied='+'), 4750 'A/mu' : Item(status=' ', wc_rev='-', copied='+'), 4751 'A/C' : Item(status=' ', wc_rev='-', copied='+'), 4752 'A/D' : Item(status=' ', wc_rev='-', copied='+'), 4753 'A/D/gamma' : Item(status=' ', wc_rev='-', copied='+'), 4754 'A/D/G' : Item(status=' ', wc_rev='-', copied='+'), 4755 'A/D/G/pi' : Item(status=' ', wc_rev='-', copied='+'), 4756 'A/D/G/rho' : Item(status=' ', wc_rev='-', copied='+'), 4757 'A/D/G/tau' : Item(status=' ', wc_rev='-', copied='+'), 4758 'A/D/H' : Item(status=' ', wc_rev='-', copied='+'), 4759 'A/D/H/chi' : Item(status=' ', wc_rev='-', copied='+'), 4760 'A/D/H/omega' : Item(status=' ', wc_rev='-', copied='+'), 4761 'A/D/H/psi' : Item(status=' ', wc_rev='-', copied='+'), 4762 'A/new_file' : Item(status='A ', wc_rev=0), 4763 'iota' : Item(status=' ', wc_rev=2), 4764 }) 4765 return expected_status 4766 4767 # The status of the new and old scenarios should be identical... 4768 expected_status = get_status(wc2) 4769 ### The following fails, as of Apr 6, 2010. The problem is that A/new_file 4770 ### has been *added* within a copy, yet the wc_db datastore cannot 4771 ### differentiate this from a copied-child. As a result, new_file is 4772 ### reported as a (M)odified node, rather than (A)dded. 4773 svntest.actions.run_and_verify_status(wc2, expected_status) 4774 4775 # ...except for the revision of the root of the WC and iota, because 4776 # above 'A' was the target of the update, not the WC root. 4777 expected_status = get_status(sbox.wc_dir) 4778 expected_status.tweak('', 'iota', wc_rev=1) 4779 svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status) 4780 4781 ### Do we need to do more to confirm we got what we want here? 4782 4783#---------------------------------------------------------------------- 4784def set_deep_depth_on_target_with_shallow_children(sbox): 4785 "infinite --set-depth adds shallow children" 4786 4787 # Regardless of what depth the update target is at, if it has shallow 4788 # subtrees and we update --set-depth infinity, these shallow subtrees 4789 # should be populated. 4790 # 4791 # See http://svn.haxx.se/dev/archive-2009-04/0344.shtml. 4792 4793 sbox.build() 4794 wc_dir = sbox.wc_dir 4795 4796 # Some paths we'll care about 4797 A_path = sbox.ospath('A') 4798 B_path = sbox.ospath('A/B') 4799 D_path = sbox.ospath('A/D') 4800 4801 # Trim the tree: Set A/B to depth empty and A/D to depth immediates. 4802 expected_output = svntest.wc.State(wc_dir, { 4803 'A/B/E' : Item(status='D '), 4804 'A/B/lambda' : Item(status='D '), 4805 'A/B/F' : Item(status='D '), 4806 }) 4807 4808 expected_disk = svntest.main.greek_state.copy() 4809 expected_disk.remove('A/B/F', 4810 'A/B/lambda', 4811 'A/B/E', 4812 'A/B/E/alpha', 4813 'A/B/E/beta') 4814 4815 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 4816 expected_status.remove('A/B/F', 4817 'A/B/lambda', 4818 'A/B/E', 4819 'A/B/E/alpha', 4820 'A/B/E/beta') 4821 4822 svntest.actions.run_and_verify_update(wc_dir, 4823 expected_output, 4824 expected_disk, 4825 expected_status, 4826 [], True, 4827 '--set-depth', 'empty', 4828 B_path) 4829 4830 expected_output = svntest.wc.State(wc_dir, { 4831 'A/D/G/pi' : Item(status='D '), 4832 'A/D/G/rho' : Item(status='D '), 4833 'A/D/G/tau' : Item(status='D '), 4834 'A/D/H/chi' : Item(status='D '), 4835 'A/D/H/omega' : Item(status='D '), 4836 'A/D/H/psi' : Item(status='D '), 4837 }) 4838 4839 expected_status.remove('A/D/G/pi', 4840 'A/D/G/rho', 4841 'A/D/G/tau', 4842 'A/D/H/chi', 4843 'A/D/H/omega', 4844 'A/D/H/psi') 4845 4846 expected_disk.remove('A/D/G/pi', 4847 'A/D/G/rho', 4848 'A/D/G/tau', 4849 'A/D/H/chi', 4850 'A/D/H/omega', 4851 'A/D/H/psi') 4852 4853 svntest.actions.run_and_verify_update(wc_dir, 4854 expected_output, 4855 expected_disk, 4856 expected_status, 4857 [], True, 4858 '--set-depth', 'immediates', 4859 D_path) 4860 4861 # Now update A with --set-depth infinity. All the subtrees we 4862 # removed above should come back. 4863 expected_output = svntest.wc.State(wc_dir, { 4864 'A/B/lambda' : Item(status='A '), 4865 'A/B/F' : Item(status='A '), 4866 'A/B/E' : Item(status='A '), 4867 'A/B/E/alpha' : Item(status='A '), 4868 'A/B/E/beta' : Item(status='A '), 4869 'A/D/G/pi' : Item(status='A '), 4870 'A/D/G/rho' : Item(status='A '), 4871 'A/D/G/tau' : Item(status='A '), 4872 'A/D/H/chi' : Item(status='A '), 4873 'A/D/H/omega' : Item(status='A '), 4874 'A/D/H/psi' : Item(status='A '), 4875 }) 4876 4877 expected_disk = svntest.main.greek_state.copy() 4878 4879 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 4880 4881 svntest.actions.run_and_verify_update(wc_dir, 4882 expected_output, 4883 expected_disk, 4884 expected_status, 4885 [], True, 4886 '--set-depth', 'infinity', 4887 A_path) 4888 4889#---------------------------------------------------------------------- 4890 4891def update_wc_of_dir_to_rev_not_containing_this_dir(sbox): 4892 "update wc of dir to rev not containing this dir" 4893 4894 sbox.build() 4895 4896 # Create working copy of 'A' directory 4897 A_url = sbox.repo_url + "/A" 4898 other_wc_dir = sbox.add_wc_path("other") 4899 svntest.actions.run_and_verify_svn(None, [], "co", A_url, other_wc_dir) 4900 4901 # Delete 'A' directory from repository 4902 svntest.actions.run_and_verify_svn(None, [], "rm", A_url, "-m", "") 4903 4904 # Try to update working copy of 'A' directory 4905 svntest.actions.run_and_verify_svn(None, 4906 "svn: E160005: Target path '/A' does not exist", 4907 "up", other_wc_dir) 4908 4909#---------------------------------------------------------------------- 4910# Test for issue #3569 svn update --depth <DEPTH> allows making a working 4911# copy incomplete. 4912@Issue(3569) 4913def update_empty_hides_entries(sbox): 4914 "svn up --depth empty hides entries for next update" 4915 sbox.build() 4916 wc_dir = sbox.wc_dir 4917 4918 expected_disk_empty = [] 4919 expected_status_empty = [] 4920 4921 expected_disk = svntest.main.greek_state.copy() 4922 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 4923 4924 # Update to revision 0 - Removes all files from WC 4925 svntest.actions.run_and_verify_update(wc_dir, 4926 None, 4927 expected_disk_empty, 4928 expected_status_empty, 4929 [], True, 4930 '-r', '0', 4931 wc_dir) 4932 4933 # Now update back to HEAD 4934 svntest.actions.run_and_verify_update(wc_dir, 4935 None, 4936 expected_disk, 4937 expected_status, 4938 [], True, 4939 wc_dir) 4940 4941 # Update to revision 0 - Removes all files from WC 4942 svntest.actions.run_and_verify_update(wc_dir, 4943 None, 4944 expected_disk_empty, 4945 expected_status_empty, 4946 [], True, 4947 '-r', '0', 4948 wc_dir) 4949 4950 # Update the directory itself back to HEAD 4951 svntest.actions.run_and_verify_update(wc_dir, 4952 None, 4953 expected_disk_empty, 4954 expected_status_empty, 4955 [], True, 4956 '--depth', 'empty', 4957 wc_dir) 4958 4959 # Now update the rest back to head 4960 4961 # This operation is currently a NO-OP, because the WC-Crawler 4962 # tells the repository that it contains a full tree of the HEAD 4963 # revision. 4964 svntest.actions.run_and_verify_update(wc_dir, 4965 None, 4966 expected_disk, 4967 expected_status, 4968 check_props=True) 4969 4970#---------------------------------------------------------------------- 4971# Test for issue #3573 'local non-inheritable mergeinfo changes not 4972# properly merged with updated mergeinfo' 4973@SkipUnless(server_has_mergeinfo) 4974def mergeinfo_updates_merge_with_local_mods(sbox): 4975 "local mergeinfo changes are merged with updates" 4976 4977 # Copy A to A_COPY in r2, and make some changes to A_COPY in r3-r6. 4978 sbox.build() 4979 wc_dir = sbox.wc_dir 4980 expected_disk, expected_status = set_up_branch(sbox) 4981 4982 # Some paths we'll care about 4983 A_path = sbox.ospath('A') 4984 A_COPY_path = sbox.ospath('A_COPY') 4985 4986 # Merge -c3 from A to A_COPY at --depth empty, commit as r7. 4987 ### 4988 ### No, we are not checking the merge output for these simple 4989 ### merges. This is already covered *TO DEATH* in merge_tests.py. 4990 ### 4991 svntest.actions.run_and_verify_svn(None, [], 'up', wc_dir) 4992 svntest.actions.run_and_verify_svn(None, [], 4993 'merge', '-c3', '--depth', 'empty', 4994 sbox.repo_url + '/A', A_COPY_path) 4995 svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 4996 'Merge r3 from A to A_COPY at depth empty', 4997 wc_dir) 4998 # Merge -c5 from A to A_COPY (at default --depth infinity), commit as r8. 4999 svntest.actions.run_and_verify_svn(None, [], 'up', wc_dir) 5000 svntest.actions.run_and_verify_svn(None, [], 5001 'merge', '-c5', 5002 sbox.repo_url + '/A', A_COPY_path) 5003 svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 5004 'Merge r5 from A to A_COPY', wc_dir) 5005 5006 # Update WC to r7, repeat merge of -c3 from A to A_COPY but this 5007 # time do it at --depth infinity. Confirm that the mergeinfo 5008 # on A_COPY is no longer inheritable. 5009 svntest.actions.run_and_verify_svn(None, [], 'up', '-r7', wc_dir) 5010 svntest.actions.run_and_verify_svn(None, [], 5011 'merge', '-c3', '--depth', 'infinity', 5012 sbox.repo_url + '/A', A_COPY_path) 5013 svntest.actions.run_and_verify_svn([A_COPY_path + " - /A:3\n"], [], 5014 'pg', SVN_PROP_MERGEINFO, '-R', 5015 A_COPY_path) 5016 5017 # Update the WC (to r8), the mergeinfo on A_COPY should now have both 5018 # the local mod from the uncommitted merge (/A:3* --> /A:3) and the change 5019 # brought down by the update (/A:3* --> /A:3*,5) leaving us with /A:3,5. 5020 ### This was failing because of issue #3573. The local mergeinfo change 5021 ### is reverted, leaving '/A:3*,5' on A_COPY. 5022 svntest.actions.run_and_verify_svn(None, [], 'up', wc_dir) 5023 svntest.actions.run_and_verify_svn([A_COPY_path + " - /A:3,5\n"], [], 5024 'pg', SVN_PROP_MERGEINFO, '-R', 5025 A_COPY_path) 5026 5027#---------------------------------------------------------------------- 5028# A regression test for a 1.7-dev crash upon updating a WC to a different 5029# revision when it contained an excluded dir. 5030def update_with_excluded_subdir(sbox): 5031 """update with an excluded subdir""" 5032 sbox.build() 5033 5034 wc_dir = sbox.wc_dir 5035 5036 G = os.path.join(sbox.ospath('A/D/G')) 5037 5038 # Make the directory 'G' excluded. 5039 expected_output = svntest.wc.State(wc_dir, { 5040 'A/D/G' : Item(status='D '), 5041 }) 5042 expected_disk = svntest.main.greek_state.copy() 5043 expected_disk.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau') 5044 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 5045 expected_status.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau') 5046 svntest.actions.run_and_verify_update(wc_dir, expected_output, 5047 expected_disk, expected_status, 5048 [], False, 5049 '--set-depth=exclude', G) 5050 5051 # Commit a new revision so there is something to update to. 5052 svntest.main.run_svn(None, 'mkdir', '-m', '', sbox.repo_url + '/New') 5053 5054 # Test updating the WC. 5055 expected_output = svntest.wc.State(wc_dir, { 5056 'New' : Item(status='A ') }) 5057 expected_disk.add({ 5058 'New' : Item() }) 5059 expected_status.add({ 5060 'New' : Item(status=' ') }) 5061 expected_status.tweak(wc_rev=2) 5062 svntest.actions.run_and_verify_update(wc_dir, expected_output, 5063 expected_disk, expected_status) 5064 5065#---------------------------------------------------------------------- 5066# Test for issue #3471 'svn up touches file w/ lock & svn:keywords property' 5067@Issue(3471) 5068def update_with_file_lock_and_keywords_property_set(sbox): 5069 """update with file lock & keywords property set""" 5070 sbox.build() 5071 5072 wc_dir = sbox.wc_dir 5073 5074 mu_path = sbox.ospath('A/mu') 5075 svntest.main.file_append(mu_path, '$Id$') 5076 svntest.main.run_svn(None, 'ps', 'svn:keywords', 'Id', mu_path) 5077 svntest.main.run_svn(None, 'lock', mu_path) 5078 mu_ts_before_update = os.path.getmtime(mu_path) 5079 5080 # Make sure we are at a different timestamp to really notice a mtime change 5081 time.sleep(1.1) 5082 5083 # Issue #3471 manifests itself here; The timestamp of 'mu' gets updated 5084 # to the time of the last "svn up". 5085 sbox.simple_update() 5086 mu_ts_after_update = os.path.getmtime(mu_path) 5087 if (mu_ts_before_update != mu_ts_after_update): 5088 logger.warn("The timestamp of 'mu' before and after update does not match.") 5089 raise svntest.Failure 5090 5091#---------------------------------------------------------------------- 5092# Updating a nonexistent or deleted path should be a successful no-op, 5093# when there is no incoming change. In trunk@1035343, such an update 5094# within a copied directory triggered an assertion failure. 5095@Issue(3807) 5096def update_nonexistent_child_of_copy(sbox): 5097 """update a nonexistent child of a copied dir""" 5098 sbox.build() 5099 os.chdir(sbox.wc_dir) 5100 5101 svntest.main.run_svn(None, 'copy', 'A', 'A2') 5102 5103 # Try updating a nonexistent path in the copied dir. 5104 expected_output = svntest.wc.State('A2', { 5105 'nonexistent' : Item(verb='Skipped'), 5106 }) 5107 svntest.actions.run_and_verify_update(os.path.join('A2', 'nonexistent'), 5108 expected_output, None, None) 5109 5110 # Try updating a deleted path in the copied dir. 5111 svntest.main.run_svn(None, 'delete', os.path.join('A2', 'mu')) 5112 5113 expected_output = svntest.wc.State('A2', { 5114 'mu' : Item(verb='Skipped'), 5115 }) 5116 svntest.actions.run_and_verify_update(os.path.join('A2', 'mu'), 5117 expected_output, None, None) 5118 if os.path.exists('A2/mu'): 5119 raise svntest.Failure("A2/mu improperly revived") 5120 5121@Issue(3807) 5122def revive_children_of_copy(sbox): 5123 """undelete a child of a copied dir""" 5124 sbox.build() 5125 os.chdir(sbox.wc_dir) 5126 5127 chi2_path = os.path.join('A2/D/H/chi') 5128 psi2_path = os.path.join('A2/D/H/psi') 5129 5130 svntest.main.run_svn(None, 'copy', 'A', 'A2') 5131 svntest.main.run_svn(None, 'rm', chi2_path) 5132 os.unlink(psi2_path) 5133 5134 svntest.main.run_svn(None, 'revert', chi2_path, psi2_path) 5135 if not os.path.exists(chi2_path): 5136 raise svntest.Failure('chi unexpectedly non-existent') 5137 if not os.path.exists(psi2_path): 5138 raise svntest.Failure('psi unexpectedly non-existent') 5139 5140@SkipUnless(svntest.main.is_os_windows) 5141def skip_access_denied(sbox): 5142 """access denied paths should be skipped""" 5143 5144 # We need something to lock the file. 'msvcrt' looks common on Windows 5145 try: 5146 import msvcrt 5147 except ImportError: 5148 raise svntest.Skip('python msvcrt library not available') 5149 5150 sbox.build() 5151 wc_dir = sbox.wc_dir 5152 5153 iota = sbox.ospath('iota') 5154 5155 svntest.main.file_write(iota, 'Q') 5156 sbox.simple_commit() 5157 sbox.simple_update() # Update to r2 5158 5159 # Open iota for writing to keep an handle open 5160 f = open(iota, 'w') 5161 5162 # Write new text of exactly the same size to avoid the early out 5163 # on a different size without properties. 5164 f.write('R') 5165 f.flush() 5166 5167 # And lock the first byte of the file 5168 msvcrt.locking(f.fileno(), 1, 1) 5169 5170 expected_output = svntest.wc.State(wc_dir, { 5171 'iota' : Item(verb='Skipped'), 5172 }) 5173 5174 # Create expected status tree: iota isn't updated 5175 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 5176 expected_status.tweak('iota', status='M ', wc_rev=2) 5177 5178 # And now check that update skips the path 5179 # *and* status shows the path as modified. 5180 svntest.actions.run_and_verify_update(wc_dir, 5181 expected_output, 5182 None, 5183 expected_status, 5184 [], False, 5185 wc_dir, '-r', '1') 5186 5187 f.close() 5188 5189def update_to_HEAD_plus_1(sbox): 5190 "updating to HEAD+1 should fail" 5191 5192 sbox.build(read_only = True) 5193 wc_dir = sbox.wc_dir 5194 5195 # Attempt the update, expecting an error. (Sometimes the error 5196 # strings says "No such revision", sometimes "No such target 5197 # revision".) 5198 svntest.actions.run_and_verify_update(wc_dir, 5199 None, None, None, 5200 ".*E160006.*No such.*revision.*", 5201 False, 5202 wc_dir, '-r', '2') 5203 5204 other_wc = sbox.add_wc_path('other') 5205 other_url = sbox.repo_url + '/A' 5206 svntest.actions.run_and_verify_svn(None, [], 5207 'co', other_url, other_wc) 5208 svntest.actions.run_and_verify_update(other_wc, 5209 None, None, None, 5210 ".*E160006.*No such.*revision.*", 5211 False, 5212 other_wc, '-r', '2') 5213 5214def update_moved_dir_leaf_del(sbox): 5215 "update locally moved dir with leaf del" 5216 sbox.build() 5217 wc_dir = sbox.wc_dir 5218 5219 svntest.main.run_svn(False, 'rm', '-m', 'remove /A/B/E/alpha', 5220 sbox.repo_url + "/A/B/E/alpha") 5221 sbox.simple_move("A/B/E", "A/B/E2") 5222 5223 # Produce a tree conflict by updating the working copy to the 5224 # revision which removed A/B/E/alpha. The deletion collides with 5225 # the local move of A/B/E to A/B/E2. 5226 expected_output = svntest.wc.State(wc_dir, { 5227 'A/B/E' : Item(status=' ', treeconflict='C'), 5228 'A/B/E/alpha' : Item(status=' ', treeconflict='D'), 5229 }) 5230 expected_disk = svntest.main.greek_state.copy() 5231 expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E') 5232 expected_disk.add({ 5233 'A/B/E2' : Item(), 5234 'A/B/E2/alpha' : Item(contents="This is the file 'alpha'.\n"), 5235 'A/B/E2/beta' : Item(contents="This is the file 'beta'.\n"), 5236 }) 5237 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 5238 expected_status.add({ 5239 'A/B/E2' : Item(status='A ', copied='+', wc_rev='-', 5240 moved_from='A/B/E'), 5241 'A/B/E2/beta' : Item(status=' ', copied='+', wc_rev='-'), 5242 'A/B/E2/alpha' : Item(status=' ', copied='+', wc_rev='-'), 5243 }) 5244 expected_status.remove('A/B/E/alpha') 5245 expected_status.tweak('A/B/E', status='D ', treeconflict='C', 5246 moved_to='A/B/E2') 5247 expected_status.tweak('A/B/E/beta', status='D ') 5248 svntest.actions.run_and_verify_update(wc_dir, 5249 expected_output, 5250 expected_disk, 5251 expected_status, 5252 check_props=True) 5253 5254 # Now resolve the conflict, using --accept=mine-conflict applying 5255 # the update to A/B/E2 5256 svntest.actions.run_and_verify_svn(None, [], 5257 'resolve', 5258 '--accept=mine-conflict', 5259 sbox.ospath('A/B/E')) 5260 expected_status.tweak('A/B/E', treeconflict=None) 5261 expected_status.remove('A/B/E2/alpha') 5262 svntest.actions.run_and_verify_status(wc_dir, expected_status) 5263 5264@Issue(3144,3630) 5265# Like break_moved_dir_edited_leaf_del, but with --accept=mine-conflict 5266def update_moved_dir_edited_leaf_del(sbox): 5267 "update locally moved dir with edited leaf del" 5268 sbox.build() 5269 wc_dir = sbox.wc_dir 5270 5271 svntest.main.run_svn(False, 'rm', '-m', 'remove /A/B/E/alpha', 5272 sbox.repo_url + "/A/B/E/alpha") 5273 sbox.simple_move("A/B/E", "A/B/E2") 5274 svntest.main.file_write(sbox.ospath('A/B/E2/alpha'), 5275 "This is a changed 'alpha'.\n") 5276 5277 # Produce a tree conflict by updating the working copy to the 5278 # revision which removed A/B/E/alpha. The deletion collides with 5279 # the local move of A/B/E to A/B/E2. 5280 expected_output = svntest.wc.State(wc_dir, { 5281 'A/B/E' : Item(status=' ', treeconflict='C'), 5282 'A/B/E/alpha' : Item(status=' ', treeconflict='D'), 5283 }) 5284 expected_disk = svntest.main.greek_state.copy() 5285 expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E') 5286 expected_disk.add({ 5287 'A/B/E2' : Item(), 5288 'A/B/E2/alpha' : Item(contents="This is a changed 'alpha'.\n"), 5289 'A/B/E2/beta' : Item(contents="This is the file 'beta'.\n"), 5290 }) 5291 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 5292 expected_status.add({ 5293 'A/B/E2' : Item(status='A ', copied='+', wc_rev='-', 5294 moved_from='A/B/E'), 5295 'A/B/E2/beta' : Item(status=' ', copied='+', wc_rev='-'), 5296 'A/B/E2/alpha' : Item(status='M ', copied='+', wc_rev='-'), 5297 }) 5298 expected_status.remove('A/B/E/alpha') 5299 expected_status.tweak('A/B/E', status='D ', treeconflict='C', 5300 moved_to='A/B/E2') 5301 expected_status.tweak('A/B/E/beta', status='D ') 5302 svntest.actions.run_and_verify_update(wc_dir, 5303 expected_output, 5304 expected_disk, 5305 expected_status, 5306 check_props=True) 5307 5308 # Now resolve the conflict, using --accept=mine-conflict. 5309 # This should apply the update to A/B/E2, and flag a tree 5310 # conflict on A/B/E2/alpha (incoming delete vs. local edit) 5311 svntest.actions.run_and_verify_svn(None, [], 5312 'resolve', 5313 '--accept=mine-conflict', 5314 sbox.ospath('A/B/E')) 5315 expected_status.tweak('A/B/E', treeconflict=None) 5316 expected_status.tweak('A/B/E2/alpha', status='A ', copied='+', wc_rev='-', 5317 entry_status=' ', treeconflict='C') 5318 svntest.actions.run_and_verify_status(wc_dir, expected_status) 5319 5320def update_moved_dir_file_add(sbox): 5321 "update locally moved dir with incoming file" 5322 sbox.build() 5323 wc_dir = sbox.wc_dir 5324 foo_path = "A/B/E/foo" 5325 foo_content = "This is the file 'foo'.\n" 5326 5327 svntest.main.file_write(sbox.ospath(foo_path), foo_content, 'wb') 5328 sbox.simple_add(foo_path) 5329 sbox.simple_commit() 5330 # update to go back in time, before the last commit 5331 svntest.main.run_svn(False, 'update', '-r', '1', wc_dir) 5332 sbox.simple_move("A/B/E", "A/B/E2") 5333 5334 # Produce a tree conflict by updating the working copy to the 5335 # revision which created A/B/E/foo. The addition collides with 5336 # the local move of A/B/E to A/B/E2. 5337 expected_output = svntest.wc.State(wc_dir, { 5338 'A/B/E' : Item(status=' ', treeconflict='C'), 5339 'A/B/E/foo' : Item(status=' ', treeconflict='A'), 5340 }) 5341 expected_disk = svntest.main.greek_state.copy() 5342 expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E') 5343 expected_disk.add({ 5344 'A/B/E2' : Item(), 5345 'A/B/E2/alpha' : Item(contents="This is the file 'alpha'.\n"), 5346 'A/B/E2/beta' : Item(contents="This is the file 'beta'.\n"), 5347 }) 5348 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 5349 expected_status.add({ 5350 'A/B/E/foo' : Item(status='D ', wc_rev='2'), 5351 'A/B/E2' : Item(status='A ', copied='+', wc_rev='-', 5352 moved_from='A/B/E'), 5353 'A/B/E2/beta' : Item(status=' ', copied='+', wc_rev='-'), 5354 'A/B/E2/alpha' : Item(status=' ', copied='+', wc_rev='-'), 5355 }) 5356 expected_status.tweak('A/B/E', status='D ', treeconflict='C', 5357 moved_to='A/B/E2') 5358 expected_status.tweak('A/B/E/alpha', status='D ') 5359 expected_status.tweak('A/B/E/beta', status='D ') 5360 svntest.actions.run_and_verify_update(wc_dir, 5361 expected_output, 5362 expected_disk, 5363 expected_status, 5364 check_props=True) 5365 5366 # Now resolve the conflict, using --accept=mine-conflict. 5367 # This should apply the update to A/B/E2, adding A/B/E2/foo. 5368 svntest.actions.run_and_verify_svn(None, [], 5369 'resolve', 5370 '--accept=mine-conflict', 5371 sbox.ospath('A/B/E')) 5372 # the incoming file should auto-merge 5373 expected_status.tweak('A/B/E', treeconflict=None) 5374 expected_status.add({ 5375 'A/B/E2/foo' : Item(status=' ', copied='+', wc_rev='-'), 5376 }) 5377 svntest.actions.run_and_verify_status(wc_dir, expected_status) 5378 5379 5380def update_moved_dir_dir_add(sbox): 5381 "update locally moved dir with incoming dir" 5382 sbox.build() 5383 wc_dir = sbox.wc_dir 5384 foo_path = "A/B/E/foo" 5385 bar_path = "A/B/E/foo/bar" 5386 bar_content = "This is the file 'bar'.\n" 5387 5388 sbox.simple_mkdir(foo_path) 5389 svntest.main.file_write(sbox.ospath(bar_path), bar_content, 'wb') 5390 sbox.simple_add(bar_path) 5391 sbox.simple_commit() 5392 # update to go back in time, before the last commit 5393 svntest.main.run_svn(False, 'update', '-r', '1', wc_dir) 5394 sbox.simple_move("A/B/E", "A/B/E2") 5395 5396 # the incoming file should auto-merge 5397 expected_output = svntest.wc.State(wc_dir, { 5398 'A/B/E' : Item(status=' ', treeconflict='C'), 5399 'A/B/E/foo' : Item(status=' ', treeconflict='A'), 5400 'A/B/E/foo/bar' : Item(status=' ', treeconflict='A'), 5401 }) 5402 expected_disk = svntest.main.greek_state.copy() 5403 expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E') 5404 expected_disk.add({ 5405 'A/B/E2' : Item(), 5406 'A/B/E2/alpha' : Item(contents="This is the file 'alpha'.\n"), 5407 'A/B/E2/beta' : Item(contents="This is the file 'beta'.\n"), 5408 }) 5409 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 5410 expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta', status='D ') 5411 expected_status.tweak('A/B/E', treeconflict='C', moved_to='A/B/E2') 5412 expected_status.add({ 5413 'A/B/E/foo' : Item(status='D ', wc_rev='2'), 5414 'A/B/E/foo/bar' : Item(status='D ', wc_rev='2'), 5415 'A/B/E2' : Item(status='A ', copied='+', wc_rev='-', 5416 moved_from='A/B/E'), 5417 'A/B/E2/beta' : Item(status=' ', copied='+', wc_rev='-'), 5418 'A/B/E2/alpha' : Item(status=' ', copied='+', wc_rev='-'), 5419 }) 5420 svntest.actions.run_and_verify_update(wc_dir, 5421 expected_output, 5422 expected_disk, 5423 expected_status, 5424 check_props=True) 5425 svntest.actions.run_and_verify_svn(None, [], 5426 'resolve', 5427 '--recursive', 5428 '--accept=mine-conflict', wc_dir) 5429 expected_status.tweak(treeconflict=None) 5430 expected_status.add({ 5431 'A/B/E2/foo' : Item(status=' ', copied='+', wc_rev='-'), 5432 'A/B/E2/foo/bar' : Item(status=' ', copied='+', wc_rev='-'), 5433 }) 5434 svntest.actions.run_and_verify_status(wc_dir, expected_status) 5435 5436@Issue(4037) 5437def update_moved_dir_file_move(sbox): 5438 "update locally moved dir with incoming file move" 5439 sbox.build() 5440 wc_dir = sbox.wc_dir 5441 5442 sbox.simple_move("A/B/E/alpha", "A/B/F/alpha") 5443 sbox.simple_commit() 5444 # update to go back in time, before the previous commit 5445 svntest.main.run_svn(False, 'update', '-r', '1', wc_dir) 5446 sbox.simple_move("A/B/E", "A/B/E2") 5447 5448 # The incoming "move" creates a tree-conflict as an incoming change 5449 # in a local move. We don't yet track moves on the server so we 5450 # don't recognise the incoming change as a move. 5451 expected_output = svntest.wc.State(wc_dir, { 5452 'A/B/E' : Item(status=' ', treeconflict='C'), 5453 'A/B/E/alpha' : Item(status=' ', treeconflict='D'), 5454 'A/B/F/alpha' : Item(status='A '), 5455 }) 5456 expected_disk = svntest.main.greek_state.copy() 5457 expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E') 5458 expected_disk.add({ 5459 'A/B/E2' : Item(), 5460 'A/B/E2/alpha' : Item(contents="This is the file 'alpha'.\n"), 5461 'A/B/E2/beta' : Item(contents="This is the file 'beta'.\n"), 5462 'A/B/F/alpha' : Item(contents="This is the file 'alpha'.\n"), 5463 }) 5464 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 5465 expected_status.remove('A/B/E/alpha') 5466 expected_status.tweak('A/B/E', status='D ', treeconflict='C', 5467 moved_to='A/B/E2') 5468 expected_status.tweak('A/B/E/beta', status='D ') 5469 expected_status.add({ 5470 'A/B/F/alpha' : Item(status=' ', wc_rev='2'), 5471 'A/B/E2' : Item(status='A ', copied='+', wc_rev='-', 5472 moved_from='A/B/E'), 5473 'A/B/E2/alpha' : Item(status=' ', copied='+', wc_rev='-'), 5474 'A/B/E2/beta' : Item(status=' ', copied='+', wc_rev='-'), 5475 }) 5476 svntest.actions.run_and_verify_update(wc_dir, 5477 expected_output, 5478 expected_disk, 5479 expected_status, 5480 check_props=True) 5481 5482 # The incoming change is a delete as we don't yet track server-side 5483 # moves. Resolving the tree-conflict as "mine-conflict" applies the 5484 # delete to the move destination. 5485 svntest.actions.run_and_verify_svn(None, [], 5486 'resolve', 5487 '--accept=mine-conflict', 5488 sbox.ospath('A/B/E')) 5489 5490 expected_status.tweak('A/B/E', treeconflict=None) 5491 expected_status.remove('A/B/E2/alpha') 5492 svntest.actions.run_and_verify_status(wc_dir, expected_status) 5493 5494 5495@Issue(3144,3630) 5496def update_move_text_mod(sbox): 5497 "text mod to moved files" 5498 5499 sbox.build() 5500 wc_dir = sbox.wc_dir 5501 svntest.main.file_append(sbox.ospath('A/B/lambda'), "modified\n") 5502 svntest.main.file_append(sbox.ospath('A/B/E/beta'), "modified\n") 5503 sbox.simple_commit() 5504 sbox.simple_update(revision=1) 5505 5506 sbox.simple_move("A/B/E", "A/E2") 5507 sbox.simple_move("A/B/lambda", "A/lambda2") 5508 5509 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 5510 expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta', 'A/B/lambda', 5511 status='D ') 5512 expected_status.tweak('A/B/E', moved_to='A/E2') 5513 expected_status.tweak('A/B/lambda', moved_to='A/lambda2') 5514 expected_status.add({ 5515 'A/E2' : Item(status='A ', copied='+', wc_rev='-', 5516 moved_from='A/B/E'), 5517 'A/E2/alpha' : Item(status=' ', copied='+', wc_rev='-'), 5518 'A/E2/beta' : Item(status=' ', copied='+', wc_rev='-'), 5519 'A/lambda2' : Item(status='A ', copied='+', wc_rev='-', 5520 moved_from='A/B/lambda'), 5521 }) 5522 5523 svntest.actions.run_and_verify_status(wc_dir, expected_status) 5524 5525 expected_output = svntest.wc.State(wc_dir, { 5526 'A/B/lambda' : Item(status=' ', treeconflict='C'), 5527 'A/B/E' : Item(status=' ', treeconflict='C'), 5528 'A/B/E/beta' : Item(status=' ', treeconflict='U'), 5529 }) 5530 expected_disk = svntest.main.greek_state.copy() 5531 expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E', 'A/B/lambda') 5532 expected_disk.add({ 5533 'A/E2' : Item(), 5534 'A/E2/alpha' : Item(contents="This is the file 'alpha'.\n"), 5535 'A/E2/beta' : Item(contents="This is the file 'beta'.\n"), 5536 'A/lambda2' : Item(contents="This is the file 'lambda'.\n"), 5537 }) 5538 expected_status.tweak(wc_rev=2) 5539 expected_status.tweak('A/B/E', 'A/B/lambda', treeconflict='C') 5540 expected_status.tweak('A/E2', 'A/E2/alpha', 'A/E2/beta', 'A/lambda2', 5541 wc_rev='-') 5542 svntest.actions.run_and_verify_update(wc_dir, 5543 expected_output, 5544 expected_disk, 5545 expected_status, 5546 check_props=True) 5547 5548 svntest.actions.run_and_verify_svn(None, [], 5549 'resolve', 5550 '--recursive', 5551 '--accept=mine-conflict', 5552 wc_dir) 5553 5554 expected_status.tweak('A/B/E', 'A/B/lambda', treeconflict=None) 5555 svntest.actions.run_and_verify_status(wc_dir, expected_status) 5556 5557 expected_disk.tweak('A/E2/beta', 5558 contents="This is the file 'beta'.\nmodified\n"), 5559 expected_disk.tweak('A/lambda2', 5560 contents="This is the file 'lambda'.\nmodified\n"), 5561 svntest.actions.verify_disk(wc_dir, expected_disk, check_props = True) 5562 5563 5564@Issue(3144,3630) 5565def update_nested_move_text_mod(sbox): 5566 "text mod to moved file in moved dir" 5567 5568 sbox.build() 5569 wc_dir = sbox.wc_dir 5570 svntest.main.file_append(sbox.ospath('A/B/E/alpha'), "modified\n") 5571 sbox.simple_commit() 5572 sbox.simple_update(revision=1) 5573 5574 sbox.simple_move("A/B/E", "A/E2") 5575 sbox.simple_move("A/E2/alpha", "A/alpha2") 5576 5577 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 5578 expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta', status='D ') 5579 expected_status.tweak('A/B/E', moved_to='A/E2') 5580 expected_status.add({ 5581 'A/E2' : Item(status='A ', copied='+', wc_rev='-', 5582 moved_from='A/B/E'), 5583 'A/E2/alpha' : Item(status='D ', copied='+', wc_rev='-', 5584 moved_to='A/alpha2'), 5585 'A/E2/beta' : Item(status=' ', copied='+', wc_rev='-'), 5586 'A/alpha2' : Item(status='A ', copied='+', wc_rev='-', 5587 moved_from='A/E2/alpha'), 5588 }) 5589 5590 svntest.actions.run_and_verify_status(wc_dir, expected_status) 5591 5592 expected_output = svntest.wc.State(wc_dir, { 5593 'A/B/E' : Item(status=' ', treeconflict='C'), 5594 'A/B/E/alpha' : Item(status=' ', treeconflict='U'), 5595 }) 5596 expected_disk = svntest.main.greek_state.copy() 5597 expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E') 5598 expected_disk.add({ 5599 'A/E2' : Item(), 5600 'A/E2/beta' : Item(contents="This is the file 'beta'.\n"), 5601 'A/alpha2' : Item(contents="This is the file 'alpha'.\n"), 5602 }) 5603 expected_status.tweak(wc_rev=2) 5604 expected_status.tweak('A/B/E', treeconflict='C') 5605 expected_status.tweak('A/E2', 'A/E2/alpha', 'A/E2/beta', 'A/alpha2', 5606 wc_rev='-') 5607 svntest.actions.run_and_verify_update(wc_dir, 5608 expected_output, 5609 expected_disk, 5610 expected_status, 5611 check_props=True) 5612 5613 svntest.actions.run_and_verify_svn(None, [], 5614 'resolve', 5615 '--recursive', 5616 '--accept=mine-conflict', 5617 wc_dir) 5618 5619 expected_status.tweak('A/B/E', treeconflict=None) 5620 svntest.actions.run_and_verify_status(wc_dir, expected_status) 5621 5622 expected_disk.tweak('A/alpha2', 5623 contents="This is the file 'alpha'.\nmodified\n"), 5624 svntest.actions.verify_disk(wc_dir, expected_disk, check_props = True) 5625 5626def update_with_parents_and_exclude(sbox): 5627 "bring a subtree in over an excluded path" 5628 5629 sbox.build(read_only = True) 5630 wc_dir = sbox.wc_dir 5631 5632 # Now we are going to exclude A 5633 expected_output = svntest.wc.State(wc_dir, { 5634 'A' : Item(status='D '), 5635 }) 5636 5637 expected_status = svntest.wc.State(wc_dir, { 5638 '' : Item(status=' ', wc_rev='1'), 5639 'iota' : Item(status=' ', wc_rev='1'), 5640 }) 5641 5642 svntest.actions.run_and_verify_update(wc_dir, 5643 expected_output, 5644 None, 5645 expected_status, 5646 [], False, 5647 '--set-depth', 'exclude', 5648 sbox.ospath('A')) 5649 5650 expected_output = svntest.wc.State(wc_dir, { 5651 'A' : Item(status='A '), 5652 'A/B' : Item(status='A '), 5653 'A/B/F' : Item(status='A '), 5654 'A/B/E' : Item(status='A '), 5655 'A/B/E/beta' : Item(status='A '), 5656 'A/B/E/alpha' : Item(status='A '), 5657 'A/B/lambda' : Item(status='A '), 5658 }) 5659 5660 expected_status = svntest.wc.State(wc_dir, { 5661 '' : Item(status=' ', wc_rev='1'), 5662 'A' : Item(status=' ', wc_rev='1'), 5663 'A/B' : Item(status=' ', wc_rev='1'), 5664 'A/B/F' : Item(status=' ', wc_rev='1'), 5665 'A/B/E' : Item(status=' ', wc_rev='1'), 5666 'A/B/E/beta' : Item(status=' ', wc_rev='1'), 5667 'A/B/E/alpha' : Item(status=' ', wc_rev='1'), 5668 'A/B/lambda' : Item(status=' ', wc_rev='1'), 5669 'iota' : Item(status=' ', wc_rev='1'), 5670 }) 5671 5672 svntest.actions.run_and_verify_update(wc_dir, 5673 expected_output, 5674 None, 5675 expected_status, 5676 [], False, 5677 '--parents', 5678 sbox.ospath('A/B')) 5679 5680@Issue(4288) 5681def update_edit_delete_obstruction(sbox): 5682 "obstructions shouldn't cause update failures" 5683 5684 sbox.build() 5685 wc_dir = sbox.wc_dir 5686 5687 # r2 5688 sbox.simple_rm('A/B','iota') 5689 svntest.main.file_append(sbox.ospath('A/mu'), "File change") 5690 sbox.simple_propset('key', 'value', 'A/D', 'A/D/G') 5691 sbox.simple_commit() 5692 5693 # r3 5694 sbox.simple_mkdir('iota') 5695 sbox.simple_copy('A/D/gamma', 'A/B') 5696 sbox.simple_rm('A/D/H/chi') 5697 sbox.simple_commit() 5698 5699 sbox.simple_update('', 1) 5700 5701 # Create obstructions 5702 svntest.main.safe_rmtree(sbox.ospath('A/B')) 5703 svntest.main.file_append(sbox.ospath('A/B'), "Obstruction") 5704 5705 svntest.main.safe_rmtree(sbox.ospath('A/D')) 5706 svntest.main.file_append(sbox.ospath('A/D'), "Obstruction") 5707 5708 os.remove(sbox.ospath('iota')) 5709 os.mkdir(sbox.ospath('iota')) 5710 5711 os.remove(sbox.ospath('A/mu')) 5712 os.mkdir(sbox.ospath('A/mu')) 5713 5714 expected_status = svntest.wc.State(wc_dir, { 5715 '' : Item(status=' ', wc_rev='2'), 5716 'A' : Item(status=' ', wc_rev='2'), 5717 'A/mu' : Item(status='~ ', treeconflict='C', wc_rev='2'), 5718 'A/D' : Item(status='~ ', treeconflict='C', wc_rev='2'), 5719 'A/D/G' : Item(status='! ', wc_rev='2'), 5720 'A/D/G/pi' : Item(status='! ', wc_rev='2'), 5721 'A/D/G/tau' : Item(status='! ', wc_rev='2'), 5722 'A/D/G/rho' : Item(status='! ', wc_rev='2'), 5723 'A/D/H' : Item(status='! ', wc_rev='2'), 5724 'A/D/H/omega' : Item(status='! ', wc_rev='2'), 5725 'A/D/H/chi' : Item(status='! ', wc_rev='2'), 5726 'A/D/H/psi' : Item(status='! ', wc_rev='2'), 5727 'A/D/gamma' : Item(status='! ', wc_rev='2'), 5728 'A/C' : Item(status=' ', wc_rev='2'), 5729 'A/B' : Item(status='~ ', treeconflict='C', wc_rev='-', 5730 entry_status='A ', entry_copied='+'), 5731 'A/B/F' : Item(status='! ', wc_rev='-', entry_copied='+'), 5732 'A/B/E' : Item(status='! ', wc_rev='-', entry_copied='+'), 5733 'A/B/E/beta' : Item(status='! ', wc_rev='-', entry_copied='+'), 5734 'A/B/E/alpha' : Item(status='! ', wc_rev='-', entry_copied='+'), 5735 'A/B/lambda' : Item(status='! ', wc_rev='-', entry_copied='+'), 5736 'iota' : Item(status='~ ', treeconflict='C', wc_rev='-', 5737 entry_status='A ', entry_copied='+'), 5738 }) 5739 expected_disk = svntest.wc.State('', { 5740 'A/D' : Item(contents="Obstruction", props={'key':'value'}), 5741 'A/C' : Item(), 5742 'A/B' : Item(contents="Obstruction"), 5743 'A/mu' : Item(), 5744 'iota' : Item(), 5745 }) 5746 5747 expected_output = svntest.wc.State(wc_dir, { 5748 'iota' : Item(status=' ', treeconflict='C'), 5749 'A/mu' : Item(status=' ', treeconflict='C'), 5750 'A/D' : Item(status=' ', treeconflict='C'), 5751 'A/D/G' : Item(status=' ', treeconflict='U'), 5752 'A/B' : Item(status=' ', treeconflict='C'), 5753 }) 5754 5755 # And now update to delete B and iota 5756 svntest.actions.run_and_verify_update(wc_dir, 5757 expected_output, 5758 expected_disk, 5759 expected_status, 5760 [], True, 5761 '-r', '2', wc_dir) 5762 5763 # Cleanup obstructions 5764 os.remove(sbox.ospath('A/B')) 5765 os.remove(sbox.ospath('A/D')) 5766 os.rmdir(sbox.ospath('iota')) 5767 os.rmdir(sbox.ospath('A/mu')) 5768 5769 # Revert to remove working nodes and tree conflicts 5770 svntest.actions.run_and_verify_svn(None, [], 5771 'revert', '-R', 5772 sbox.ospath('A/B'), 5773 sbox.ospath('A/mu'), 5774 sbox.ospath('A/D'), 5775 sbox.ospath('iota')) 5776 sbox.simple_update('', 1) 5777 5778 # Now obstruct A (as parent of the changed node), and retry 5779 svntest.main.safe_rmtree(sbox.ospath('A')) 5780 svntest.main.file_append(sbox.ospath('A'), "Obstruction") 5781 5782 # And now update to delete B and iota 5783 5784 expected_output = svntest.wc.State(wc_dir, { 5785 'A' : Item(status=' ', treeconflict='C'), 5786 'A/mu' : Item(status=' ', treeconflict='U'), 5787 'A/D' : Item(status=' ', treeconflict='U'), 5788 'A/D/G' : Item(status=' ', treeconflict='U'), 5789 'A/D/H' : Item(status=' ', treeconflict='U'), 5790 'A/D/H/chi' : Item(status=' ', treeconflict='D'), 5791 'A/B' : Item(prev_status=' ', prev_treeconflict='D', # Replacement 5792 status=' ', treeconflict='A'), 5793 'iota' : Item(status='A ', prev_status='D '), # Replacement 5794 }) 5795 5796 expected_disk = svntest.wc.State('', { 5797 'A' : Item(contents="Obstruction"), 5798 'iota' : Item(), 5799 }) 5800 5801 expected_status = svntest.wc.State(wc_dir, { 5802 '' : Item(status=' ', wc_rev='3'), 5803 'A' : Item(status='~ ', treeconflict='C', wc_rev='3'), 5804 'A/mu' : Item(status='! ', wc_rev='3'), 5805 'A/D' : Item(status='! ', wc_rev='3'), 5806 'A/D/G' : Item(status='! ', wc_rev='3'), 5807 'A/D/G/rho' : Item(status='! ', wc_rev='3'), 5808 'A/D/G/pi' : Item(status='! ', wc_rev='3'), 5809 'A/D/G/tau' : Item(status='! ', wc_rev='3'), 5810 'A/D/gamma' : Item(status='! ', wc_rev='3'), 5811 'A/D/H' : Item(status='! ', wc_rev='3'), 5812 'A/D/H/psi' : Item(status='! ', wc_rev='3'), 5813 'A/D/H/omega' : Item(status='! ', wc_rev='3'), 5814 'A/C' : Item(status='! ', wc_rev='3'), 5815 'A/B' : Item(status='! ', wc_rev='3'), 5816 'iota' : Item(status=' ', wc_rev='3'), 5817 }) 5818 5819 svntest.actions.run_and_verify_update(wc_dir, 5820 expected_output, 5821 expected_disk, 5822 expected_status, 5823 [], True, 5824 '-r', '3', wc_dir) 5825 5826def update_deleted(sbox): 5827 "update a deleted tree" 5828 5829 sbox.build(read_only = True) 5830 wc_dir = sbox.wc_dir 5831 sbox.simple_rm('A') 5832 5833 expected_output = svntest.wc.State(wc_dir, { 5834 }) 5835 5836 expected_status = svntest.wc.State(wc_dir, { 5837 }) 5838 5839 # This runs an update anchored on A, which is deleted. The update editor 5840 # shouldn't look at the ACTUAL/WORKING data in this case, but in 1.7 it did. 5841 svntest.actions.run_and_verify_update(wc_dir, 5842 expected_output, 5843 None, 5844 None, 5845 [], True, 5846 sbox.ospath('A/B')) 5847 5848@Issue(3144,3630) 5849# Like update_moved_dir_edited_leaf_del, but with --accept=theirs-conflict 5850def break_moved_dir_edited_leaf_del(sbox): 5851 "break local move of dir with edited leaf del" 5852 sbox.build() 5853 wc_dir = sbox.wc_dir 5854 5855 svntest.main.run_svn(False, 'rm', '-m', 'remove /A/B/E/alpha', 5856 sbox.repo_url + "/A/B/E/alpha") 5857 sbox.simple_move("A/B/E", "A/B/E2") 5858 svntest.main.file_write(sbox.ospath('A/B/E2/alpha'), 5859 "This is a changed 'alpha'.\n") 5860 5861 # Produce a tree conflict by updating the working copy to the 5862 # revision which removed A/B/E/alpha. The deletion collides with 5863 # the local move of A/B/E to A/B/E2. 5864 expected_output = svntest.wc.State(wc_dir, { 5865 'A/B/E' : Item(status=' ', treeconflict='C'), 5866 'A/B/E/alpha' : Item(status=' ', treeconflict='D'), 5867 }) 5868 expected_disk = svntest.main.greek_state.copy() 5869 expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E') 5870 expected_disk.add({ 5871 'A/B/E2' : Item(), 5872 'A/B/E2/alpha' : Item(contents="This is a changed 'alpha'.\n"), 5873 'A/B/E2/beta' : Item(contents="This is the file 'beta'.\n"), 5874 }) 5875 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 5876 expected_status.add({ 5877 'A/B/E2' : Item(status='A ', copied='+', wc_rev='-', 5878 moved_from='A/B/E'), 5879 'A/B/E2/beta' : Item(status=' ', copied='+', wc_rev='-'), 5880 'A/B/E2/alpha' : Item(status='M ', copied='+', wc_rev='-'), 5881 }) 5882 expected_status.remove('A/B/E/alpha') 5883 expected_status.tweak('A/B/E', status='D ', treeconflict='C', 5884 moved_to='A/B/E2') 5885 expected_status.tweak('A/B/E/beta', status='D ') 5886 svntest.actions.run_and_verify_update(wc_dir, 5887 expected_output, 5888 expected_disk, 5889 expected_status, 5890 check_props=True) 5891 5892 # Now resolve the conflict, using --accept=working 5893 # This should break the move of A/B/E to A/B/E2, leaving A/B/E2 5894 # as a copy. The deletion of A/B/E is not reverted. 5895 svntest.actions.run_and_verify_svn(None, [], 5896 'resolve', '--recursive', 5897 '--accept=working', wc_dir) 5898 expected_status.tweak('A/B/E', treeconflict=None, moved_to=None) 5899 expected_status.tweak('A/B/E2', moved_from=None) 5900 svntest.actions.run_and_verify_status(wc_dir, expected_status) 5901 5902@Issue(3144,3630) 5903def break_moved_replaced_dir(sbox): 5904 "break local move of dir plus replace" 5905 sbox.build() 5906 wc_dir = sbox.wc_dir 5907 5908 svntest.main.run_svn(False, 'rm', '-m', 'remove /A/B/E/alpha', 5909 sbox.repo_url + "/A/B/E/alpha") 5910 sbox.simple_move("A/B/E", "A/B/E2") 5911 svntest.main.file_write(sbox.ospath('A/B/E2/alpha'), 5912 "This is a changed 'alpha'.\n") 5913 5914 # Locally replace A/B/E with something else 5915 sbox.simple_copy('A/D/H', 'A/B/E') 5916 5917 # Produce a tree conflict by updating the working copy to the 5918 # revision which removed A/B/E/alpha. The deletion collides with 5919 # the local move of A/B/E to A/B/E2. 5920 expected_output = svntest.wc.State(wc_dir, { 5921 'A/B/E' : Item(status=' ', treeconflict='C'), 5922 'A/B/E/alpha' : Item(status=' ', treeconflict='D'), 5923 }) 5924 expected_disk = svntest.main.greek_state.copy() 5925 expected_disk.remove('A/B/E/alpha', 'A/B/E/beta') 5926 expected_disk.add({ 5927 'A/B/E/chi' : Item(contents="This is the file 'chi'.\n"), 5928 'A/B/E/psi' : Item(contents="This is the file 'psi'.\n"), 5929 'A/B/E/omega' : Item(contents="This is the file 'omega'.\n"), 5930 'A/B/E2' : Item(), 5931 'A/B/E2/alpha' : Item(contents="This is a changed 'alpha'.\n"), 5932 'A/B/E2/beta' : Item(contents="This is the file 'beta'.\n"), 5933 }) 5934 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 5935 expected_status.add({ 5936 'A/B/E/chi' : Item(status=' ', copied='+', wc_rev='-'), 5937 'A/B/E/psi' : Item(status=' ', copied='+', wc_rev='-'), 5938 'A/B/E/omega' : Item(status=' ', copied='+', wc_rev='-'), 5939 'A/B/E2' : Item(status='A ', copied='+', wc_rev='-', 5940 moved_from='A/B/E'), 5941 'A/B/E2/beta' : Item(status=' ', copied='+', wc_rev='-'), 5942 'A/B/E2/alpha' : Item(status='M ', copied='+', wc_rev='-'), 5943 }) 5944 expected_status.remove('A/B/E/alpha') 5945 expected_status.tweak('A/B/E', status='R ', copied='+', wc_rev='-', 5946 treeconflict='C', moved_to='A/B/E2') 5947 expected_status.tweak('A/B/E/beta', status='D ') 5948 svntest.actions.run_and_verify_update(wc_dir, 5949 expected_output, 5950 expected_disk, 5951 expected_status, 5952 check_props=True) 5953 5954 # Now resolve the conflict, using --accept=working 5955 # This should break the move of A/B/E to A/B/E2, leaving A/B/E2 5956 # as a copy. A/B/E is not reverted. 5957 svntest.actions.run_and_verify_svn(None, [], 5958 'resolve', '--recursive', 5959 '--accept=working', wc_dir) 5960 expected_status.tweak('A/B/E2', moved_from=None) 5961 expected_status.tweak('A/B/E', treeconflict=None, moved_to=None) 5962 svntest.actions.run_and_verify_status(wc_dir, expected_status) 5963 5964@Issue(4295) 5965def update_removes_switched(sbox): 5966 "update completely removes switched node" 5967 5968 sbox.build(create_wc = False) 5969 5970 wc_dir = sbox.wc_dir 5971 repo_url = sbox.repo_url 5972 5973 svntest.actions.run_and_verify_svn(None, [], 5974 'cp', repo_url + '/A', 5975 repo_url + '/AA', '-m', 'Q') 5976 5977 svntest.actions.run_and_verify_svn(None, [], 5978 'co', repo_url + '/A', sbox.wc_dir) 5979 svntest.actions.run_and_verify_svn(None, [], 5980 'switch', repo_url + '/AA/B', 5981 wc_dir + '/B') 5982 5983 svntest.actions.run_and_verify_svn(None, [], 5984 'rm', repo_url + '/AA/B', '-m', 'Q') 5985 5986 expected_output = svntest.wc.State(wc_dir, { 5987 'B' : Item(status='D '), 5988 }) 5989 expected_status = svntest.wc.State(wc_dir, { 5990 '' : Item(status=' ', wc_rev='3'), 5991 'D' : Item(status=' ', wc_rev='3'), 5992 'D/G' : Item(status=' ', wc_rev='3'), 5993 'D/G/rho' : Item(status=' ', wc_rev='3'), 5994 'D/G/pi' : Item(status=' ', wc_rev='3'), 5995 'D/G/tau' : Item(status=' ', wc_rev='3'), 5996 'D/H' : Item(status=' ', wc_rev='3'), 5997 'D/H/omega' : Item(status=' ', wc_rev='3'), 5998 'D/H/chi' : Item(status=' ', wc_rev='3'), 5999 'D/H/psi' : Item(status=' ', wc_rev='3'), 6000 'D/gamma' : Item(status=' ', wc_rev='3'), 6001 'C' : Item(status=' ', wc_rev='3'), 6002 'mu' : Item(status=' ', wc_rev='3'), 6003 }) 6004 6005 # Before r1435684 the inherited properties code would try to fetch 6006 # inherited properties for ^/AA/B and fail. 6007 # 6008 # The inherited properties fetch code would then bail and forget to reset 6009 # the ra-session URL back to its original value. 6010 # 6011 # After that the update code (which ignored the specific error code) was 6012 # continued the update against /AA/B (url of missing switched path) 6013 # instead of against A (the working copy url). 6014 6015 # This update removes 'A/B', since its in-repository location is removed. 6016 svntest.actions.run_and_verify_update(wc_dir, 6017 expected_output, 6018 None, 6019 expected_status) 6020 6021 expected_output = svntest.wc.State(wc_dir, { 6022 'B' : Item(status='A '), 6023 'B/lambda' : Item(status='A '), 6024 'B/E' : Item(status='A '), 6025 'B/E/alpha' : Item(status='A '), 6026 'B/E/beta' : Item(status='A '), 6027 'B/F' : Item(status='A '), 6028 }) 6029 expected_status = svntest.wc.State(wc_dir, { 6030 '' : Item(status=' ', wc_rev='3'), 6031 'D' : Item(status=' ', wc_rev='3'), 6032 'D/G' : Item(status=' ', wc_rev='3'), 6033 'D/G/rho' : Item(status=' ', wc_rev='3'), 6034 'D/G/pi' : Item(status=' ', wc_rev='3'), 6035 'D/G/tau' : Item(status=' ', wc_rev='3'), 6036 'D/H' : Item(status=' ', wc_rev='3'), 6037 'D/H/omega' : Item(status=' ', wc_rev='3'), 6038 'D/H/chi' : Item(status=' ', wc_rev='3'), 6039 'D/H/psi' : Item(status=' ', wc_rev='3'), 6040 'D/gamma' : Item(status=' ', wc_rev='3'), 6041 'B' : Item(status=' ', wc_rev='3'), 6042 'B/E' : Item(status=' ', wc_rev='3'), 6043 'B/E/alpha' : Item(status=' ', wc_rev='3'), 6044 'B/E/beta' : Item(status=' ', wc_rev='3'), 6045 'B/F' : Item(status=' ', wc_rev='3'), 6046 'B/lambda' : Item(status=' ', wc_rev='3'), 6047 'C' : Item(status=' ', wc_rev='3'), 6048 'mu' : Item(status=' ', wc_rev='3'), 6049 }) 6050 6051 # And this final update brings back the node, as it was before switching. 6052 svntest.actions.run_and_verify_update(wc_dir, 6053 expected_output, 6054 None, 6055 expected_status) 6056 6057@Issue(3192) 6058def incomplete_overcomplete(sbox): 6059 "verify editor v1 incomplete behavior" 6060 6061 sbox.build() 6062 6063 wc_dir = sbox.wc_dir 6064 repo_dir = sbox.repo_dir 6065 repo_url = sbox.repo_url 6066 6067 # r2 - Make sure we have some dir properties in a clean wc 6068 sbox.simple_rm('A', 'iota') 6069 sbox.simple_propset('keep', 'keep-value', '') 6070 sbox.simple_propset('del', 'del-value', '') 6071 sbox.simple_commit() 6072 6073 # r3 - Perform some changes that will be undone later 6074 sbox.simple_mkdir('ADDED-dir') 6075 sbox.simple_add_text('The added file', 'added-file') 6076 sbox.simple_propset('prop-added', 'value', '') 6077 sbox.simple_commit('') 6078 sbox.simple_update('') 6079 6080 r3_disk = svntest.wc.State('', { 6081 'added-file' : Item(contents="The added file"), 6082 '.' : Item(props={'prop-added':'value', 'del':'del-value', 'keep':'keep-value'}), 6083 'ADDED-dir' : Item(), 6084 }) 6085 6086 r3_status = svntest.wc.State(wc_dir, { 6087 '' : Item(status=' ', wc_rev='3'), 6088 'ADDED-dir' : Item(status=' ', wc_rev='3'), 6089 'added-file' : Item(status=' ', wc_rev='3'), 6090 }) 6091 6092 # Verify assumptions for later check 6093 svntest.actions.run_and_verify_status(wc_dir, r3_status) 6094 svntest.actions.verify_disk(wc_dir, r3_disk, check_props = True) 6095 6096 6097 # r4 - And we undo r3 6098 sbox.simple_rm('ADDED-dir', 'added-file') 6099 sbox.simple_propdel('prop-added', '') 6100 sbox.simple_commit('') 6101 6102 # r5 - Create some alternate changes 6103 sbox.simple_mkdir('NOT-ADDED-dir') 6104 sbox.simple_add_text('The not added file', 'not-added-file') 6105 sbox.simple_propset('prop-not-added', 'value', '') 6106 sbox.simple_commit('') 6107 6108 # Nothing to do to bring the wc to single revision 6109 expected_output = svntest.wc.State(wc_dir, { 6110 }) 6111 6112 r5_disk = svntest.wc.State('', { 6113 '' : Item(props={'prop-not-added':'value', 6114 'del':'del-value', 6115 'keep':'keep-value'}), 6116 'NOT-ADDED-dir' : Item(), 6117 'not-added-file' : Item(contents="The not added file"), 6118 }) 6119 6120 expected_status = svntest.wc.State(wc_dir, { 6121 '' : Item(status=' ', wc_rev='5'), 6122 'NOT-ADDED-dir' : Item(status=' ', wc_rev='5'), 6123 'not-added-file' : Item(status=' ', wc_rev='5'), 6124 }) 6125 6126 6127 svntest.actions.run_and_verify_update(wc_dir, 6128 expected_output, 6129 r5_disk, 6130 expected_status, 6131 check_props=True) 6132 6133 # And now we mark the directory incomplete, as if the update had failed 6134 # half-way through an update to r3 6135 svntest.actions.set_incomplete(wc_dir, 3) 6136 6137 # Tweak status to verify us breaking the wc 6138 expected_status.tweak('', status='! ', wc_rev=3) 6139 svntest.actions.run_and_verify_status(wc_dir, expected_status) 6140 6141 # But the working copy is still 100% at r5 6142 svntest.actions.verify_disk(wc_dir, r5_disk, check_props = True) 6143 6144 # And expect update to do the right thing even though r3 is already encoded 6145 # in the parent. This includes fixing the list of children (reported to the 6146 # server, which will report adds and deletes) and fixing the property list 6147 # (received all; client should delete properties that shouldn't be here) 6148 6149 expected_output = svntest.wc.State(wc_dir, { 6150 '' : Item(status=' U'), 6151 'not-added-file' : Item(status='D '), 6152 'ADDED-dir' : Item(status='A '), 6153 'added-file' : Item(status='A '), 6154 'NOT-ADDED-dir' : Item(status='D '), 6155 }) 6156 6157 svntest.actions.run_and_verify_update(wc_dir, 6158 expected_output, 6159 r3_disk, 6160 r3_status, 6161 [], True, 6162 wc_dir, '-r', 3) 6163 6164@Issue(4300) 6165def update_swapped_depth_dirs(sbox): 6166 "text mod to file in swapped depth dir" 6167 6168 sbox.build() 6169 wc_dir = sbox.wc_dir 6170 sbox.build() 6171 wc_dir = sbox.wc_dir 6172 svntest.main.file_append(sbox.ospath('A/B/E/alpha'), "modified\n") 6173 sbox.simple_commit() 6174 sbox.simple_update(revision=1) 6175 6176 sbox.simple_move("A/B/E", "A/E") 6177 sbox.simple_move("A/B", "A/E/B") 6178 # This is almost certainly not the right status but it's what 6179 # is currently being output so we're using it here so we 6180 # can get to the deeper problem. 6181 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 6182 expected_status.tweak("A/B", "A/B/lambda", "A/B/F", "A/B/E", 6183 "A/B/E/alpha", "A/B/E/beta", status="D ") 6184 expected_status.tweak("A/B", moved_to="A/E/B") 6185 expected_status.add({ 6186 'A/E' : Item(status='A ', copied='+', wc_rev='-', 6187 moved_from='A/E/B/E'), 6188 'A/E/B' : Item(status='A ', copied='+', wc_rev='-', 6189 moved_from='A/B'), 6190 'A/E/B/E' : Item(status='D ', copied='+', wc_rev='-', 6191 moved_to='A/E'), 6192 'A/E/B/F' : Item(status=' ', copied='+', wc_rev='-'), 6193 'A/E/B/lambda' : Item(status=' ', copied='+', wc_rev='-'), 6194 'A/E/alpha' : Item(status=' ', copied='+', wc_rev='-'), 6195 'A/E/beta' : Item(status=' ', copied='+', wc_rev='-'), 6196 'A/E/B/E/alpha': Item(status='D ', copied='+', wc_rev='-'), 6197 'A/E/B/E/beta' : Item(status='D ', copied='+', wc_rev='-'), 6198 }) 6199 6200 svntest.actions.run_and_verify_status(wc_dir, expected_status) 6201 6202 expected_output = svntest.wc.State(wc_dir, { 6203 'A/B' : Item(status=' ', treeconflict='C'), 6204 'A/B/E' : Item(status=' ', treeconflict='U'), 6205 'A/B/E/alpha' : Item(status=' ', treeconflict='U'), 6206 }) 6207 expected_disk = svntest.main.greek_state.copy() 6208 expected_disk.remove('A/B', 'A/B/lambda', 'A/B/F', 'A/B/E', 6209 'A/B/E/alpha', 'A/B/E/beta') 6210 expected_disk.add({ 6211 'A/E' : Item(), 6212 'A/E/alpha' : Item(contents="This is the file 'alpha'.\n"), 6213 'A/E/beta' : Item(contents="This is the file 'beta'.\n"), 6214 'A/E/B' : Item(), 6215 'A/E/B/lambda' : Item(contents="This is the file 'lambda'.\n"), 6216 'A/E/B/F' : Item(), 6217 }) 6218 expected_status.tweak(wc_rev=2) 6219 expected_status.tweak('A/B', treeconflict='C') 6220 expected_status.tweak('A/E', 'A/E/alpha', 'A/E/beta', 'A/E/B', 6221 'A/E/B/E', 'A/E/B/E/alpha', 'A/E/B/E/beta', 6222 'A/E/B/lambda', 'A/E/B/F', wc_rev='-') 6223 svntest.actions.run_and_verify_update(wc_dir, 6224 expected_output, 6225 expected_disk, 6226 expected_status, 6227 check_props=True) 6228 6229def move_update_props(sbox): 6230 "move-update with property mods" 6231 6232 sbox.build() 6233 wc_dir = sbox.wc_dir 6234 6235 # Commit some 'future' property changes 6236 sbox.simple_propset('propertyA', 'value1', 6237 'A/B', 'A/B/E', 'A/B/E/alpha', 'A/B/E/beta') 6238 sbox.simple_commit() 6239 sbox.simple_propset('propertyB', 'value2', 6240 'A/B', 'A/B/E', 'A/B/E/alpha', 'A/B/E/beta') 6241 sbox.simple_commit() 6242 sbox.simple_update(revision=1) 6243 6244 # Make some local property changes 6245 sbox.simple_propset('propertyB', 'value3', 6246 'A/B/E', 'A/B/E/beta') 6247 6248 sbox.simple_move("A/B", "A/B2") 6249 6250 # Update and expect a conflict 6251 expected_output = svntest.wc.State(wc_dir, { 6252 'A/B' : Item(status=' ', treeconflict='C'), 6253 'A/B/E' : Item(status=' ', treeconflict='U'), 6254 'A/B/E/alpha' : Item(status=' ', treeconflict='U'), 6255 'A/B/E/beta' : Item(status=' ', treeconflict='U'), 6256 }) 6257 expected_disk = svntest.main.greek_state.copy() 6258 expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E', 6259 'A/B/lambda', 'A/B/F', 'A/B') 6260 expected_disk.add({ 6261 'A/B2' : Item(), 6262 'A/B2/E' : Item(), 6263 'A/B2/E/alpha' : Item(contents="This is the file 'alpha'.\n"), 6264 'A/B2/E/beta' : Item(contents="This is the file 'beta'.\n"), 6265 'A/B2/F' : Item(), 6266 'A/B2/lambda' : Item(contents="This is the file 'lambda'.\n"), 6267 }) 6268 expected_disk.tweak('A/B2/E', 'A/B2/E/beta', props={'propertyB':'value3'}) 6269 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 6270 expected_status.tweak('A/B', status='D ', treeconflict='C', moved_to='A/B2') 6271 expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta', 6272 'A/B/F', 'A/B/lambda', status='D ') 6273 expected_status.add({ 6274 'A/B2' : Item(status='A ', copied='+', wc_rev='-', 6275 moved_from='A/B'), 6276 'A/B2/E' : Item(status=' M', copied='+', wc_rev='-'), 6277 'A/B2/E/beta' : Item(status=' M', copied='+', wc_rev='-'), 6278 'A/B2/E/alpha' : Item(status=' ', copied='+', wc_rev='-'), 6279 'A/B2/F' : Item(status=' ', copied='+', wc_rev='-'), 6280 'A/B2/lambda' : Item(status=' ', copied='+', wc_rev='-'), 6281 }) 6282 svntest.actions.run_and_verify_update(wc_dir, 6283 expected_output, 6284 expected_disk, 6285 expected_status, 6286 [], True, 6287 '-r', '2', wc_dir) 6288 6289 # Resolve conflict moving changes to destination without conflict 6290 svntest.actions.run_and_verify_svn(None, [], 6291 'resolve', 6292 '--accept=mine-conflict', 6293 sbox.ospath('A/B')) 6294 6295 expected_status.tweak('A/B', treeconflict=None) 6296 svntest.actions.run_and_verify_status(wc_dir, expected_status) 6297 6298 expected_disk.tweak('A/B2', 'A/B2/E/alpha', props={'propertyA' : 'value1'}) 6299 expected_disk.tweak('A/B2/E', 'A/B2/E/beta', props={'propertyA' : 'value1', 6300 'propertyB':'value3'}) 6301 svntest.actions.verify_disk(wc_dir, expected_disk, check_props = True) 6302 6303 # Further update and expect a conflict. 6304 expected_status.tweak('A/B', status='D ', treeconflict='C', moved_to='A/B2') 6305 expected_status.tweak(wc_rev=3) 6306 expected_status.tweak( 'A/B2', 'A/B2/E', 'A/B2/E/beta', 'A/B2/E/alpha', 6307 'A/B2/F', 'A/B2/lambda', wc_rev='-') 6308 svntest.actions.run_and_verify_update(wc_dir, 6309 expected_output, 6310 expected_disk, 6311 expected_status, 6312 [], True, 6313 '-r', '3', wc_dir) 6314 6315 # Resolve conflict moving changes and raising property conflicts 6316 svntest.actions.run_and_verify_svn(None, [], 6317 'resolve', 6318 '--accept=mine-conflict', 6319 sbox.ospath('A/B')) 6320 6321 expected_status.tweak('A/B', treeconflict=None) 6322 expected_status.tweak('A/B2/E', 'A/B2/E/beta', status=' C') 6323 svntest.actions.run_and_verify_status(wc_dir, expected_status) 6324 6325 expected_disk.tweak('A/B2', 'A/B2/E/alpha', props={'propertyA' : 'value1', 6326 'propertyB' : 'value2'}) 6327 expected_disk.tweak('A/B2/E', 'A/B2/E/beta', props={'propertyA' : 'value1', 6328 'propertyB' : 'value3'}) 6329 extra_files = ['dir_conflicts.prej', 'beta.prej'] 6330 svntest.actions.verify_disk(wc_dir, expected_disk, True, 6331 extra_files=extra_files) 6332 6333@Issues(3288) 6334@SkipUnless(svntest.main.is_os_windows) 6335def windows_update_backslash(sbox): 6336 "test filename with backslashes inside" 6337 6338 sbox.build() 6339 6340 wc_dir = sbox.wc_dir 6341 6342 mucc_url = sbox.repo_url 6343 6344 if mucc_url.startswith('http'): 6345 # Apache Httpd doesn't allow creating paths with '\\' in them on Windows 6346 # AH00026: found %2f (encoded '/') in URI (decoded='/svn-test-work/repositories/authz_tests-30/!svn/ver/2/A/completely\\unusable\\dir'), returning 404 6347 # 6348 # Let's use file:// to work around. 6349 mucc_url = 'file:///' + os.path.abspath(sbox.repo_dir).replace('\\', '/') 6350 6351 svntest.actions.run_and_verify_svnmucc(None, [], 6352 '-U', mucc_url, 6353 '-m', '', 6354 'mkdir', 'A/completely\\unusable\\dir') 6355 6356 # No error and a proper skip + recording in the working copy would also 6357 # be a good result. This just verifies current behavior: 6358 # 6359 # - Error via file://, svn:// or http:// with SVNPathAuthz short_circuit 6360 # 6361 # - No error via http:// with SVNPathAuthz on 6362 # (The reason is that Apache Httpd doesn't allow paths with '\\' in 6363 # them on Windows, and a subrequest-based access check returns 404. 6364 # This makes mod_dav_svn report the path as server excluded (aka 6365 # absent), which doesn't produce output when updating.) 6366 # 6367 # Since https://issues.apache.org/jira/browse/SVN-3288 is about a crash, 6368 # we're fine with either result -- that is, if `svn update' finished 6369 # without an error, we expect specific stdout and proper wc state. 6370 # If it failed, we expect to get the following error: 6371 # 6372 # svn: E155000: 'completely\unusable\dir' is not valid as filename 6373 # in directory [...] 6374 # 6375 exit_code, output, errput = svntest.main.run_svn(1, 'up', wc_dir) 6376 if exit_code == 0: 6377 verify.verify_outputs("Unexpected output", output, errput, [ 6378 "Updating '%s':\n" % wc_dir, 6379 "At revision 2.\n" 6380 ], []) 6381 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 6382 svntest.actions.run_and_verify_status(wc_dir, expected_status) 6383 elif exit_code == 1: 6384 verify.verify_outputs("Unexpected output", output, errput, 6385 None, 'svn: E155000: .* is not valid.*') 6386 else: 6387 raise verify.SVNUnexpectedExitCode(exit_code) 6388 6389def update_moved_away(sbox): 6390 "update subtree of moved away" 6391 6392 sbox.build() 6393 wc_dir = sbox.wc_dir 6394 6395 sbox.simple_add_text('new', 'new') 6396 sbox.simple_commit() 6397 6398 sbox.simple_move('A', 'A_moved') 6399 6400 # Adding prev_status=' ' and prev_treeconflict='C' to A will make 6401 # the test PASS but why are we getting two conflicts? 6402 expected_output = svntest.wc.State(wc_dir, { 6403 'A' : Item(status=' ', treeconflict='C'), 6404 }) 6405 6406 expected_disk = None 6407 expected_status = svntest.wc.State(wc_dir, { 6408 '' : Item(status=' ', wc_rev='1'), 6409 'A' : Item(status='D ', wc_rev='1', moved_to='A_moved', 6410 treeconflict='C'), 6411 'A/B' : Item(status='D ', wc_rev='1'), 6412 'A/B/E' : Item(status='D ', wc_rev='2'), 6413 'A/B/E/beta' : Item(status='D ', wc_rev='2'), 6414 'A/B/E/alpha' : Item(status='D ', wc_rev='2'), 6415 'A/B/F' : Item(status='D ', wc_rev='1'), 6416 'A/B/lambda' : Item(status='D ', wc_rev='1'), 6417 'A/D' : Item(status='D ', wc_rev='1'), 6418 'A/D/G' : Item(status='D ', wc_rev='1'), 6419 'A/D/G/pi' : Item(status='D ', wc_rev='1'), 6420 'A/D/G/tau' : Item(status='D ', wc_rev='1'), 6421 'A/D/G/rho' : Item(status='D ', wc_rev='1'), 6422 'A/D/H' : Item(status='D ', wc_rev='1'), 6423 'A/D/H/psi' : Item(status='D ', wc_rev='1'), 6424 'A/D/H/chi' : Item(status='D ', wc_rev='1'), 6425 'A/D/H/omega' : Item(status='D ', wc_rev='1'), 6426 'A/D/gamma' : Item(status='D ', wc_rev='1'), 6427 'A/C' : Item(status='D ', wc_rev='1'), 6428 'A/mu' : Item(status='D ', wc_rev='1'), 6429 'A_moved' : Item(status='A ', copied='+', wc_rev='-', 6430 moved_from='A'), 6431 'A_moved/D' : Item(status=' ', copied='+', wc_rev='-'), 6432 'A_moved/D/G' : Item(status=' ', copied='+', wc_rev='-'), 6433 'A_moved/D/G/rho' : Item(status=' ', copied='+', wc_rev='-'), 6434 'A_moved/D/G/tau' : Item(status=' ', copied='+', wc_rev='-'), 6435 'A_moved/D/G/pi' : Item(status=' ', copied='+', wc_rev='-'), 6436 'A_moved/D/H' : Item(status=' ', copied='+', wc_rev='-'), 6437 'A_moved/D/H/omega' : Item(status=' ', copied='+', wc_rev='-'), 6438 'A_moved/D/H/psi' : Item(status=' ', copied='+', wc_rev='-'), 6439 'A_moved/D/H/chi' : Item(status=' ', copied='+', wc_rev='-'), 6440 'A_moved/D/gamma' : Item(status=' ', copied='+', wc_rev='-'), 6441 'A_moved/B' : Item(status=' ', copied='+', wc_rev='-'), 6442 'A_moved/B/E' : Item(status=' ', copied='+', wc_rev='-'), 6443 'A_moved/B/E/beta' : Item(status=' ', copied='+', wc_rev='-'), 6444 'A_moved/B/E/alpha' : Item(status=' ', copied='+', wc_rev='-'), 6445 'A_moved/B/lambda' : Item(status=' ', copied='+', wc_rev='-'), 6446 'A_moved/B/F' : Item(status=' ', copied='+', wc_rev='-'), 6447 'A_moved/mu' : Item(status=' ', copied='+', wc_rev='-'), 6448 'A_moved/C' : Item(status=' ', copied='+', wc_rev='-'), 6449 'iota' : Item(status=' ', wc_rev='1'), 6450 'new' : Item(status=' ', wc_rev='2'), 6451 }) 6452 6453 # This update raises a tree-conflict on A. The conflict cannot be 6454 # resolved to update the move destination because the move source is 6455 # mixed rev. 6456 6457 # Note that this exact scenario doesn't apply to switch as we don't 6458 # allow switches with as root a shadowed node. However it is 6459 # possible to get essentially the problem with switch by invoking a 6460 # depth immedates switch on the parent of the root of the move 6461 # source. That switches the root of the move without switching the 6462 # children. 6463 svntest.actions.run_and_verify_update(wc_dir, 6464 expected_output, 6465 expected_disk, 6466 expected_status, 6467 [], False, 6468 sbox.ospath('A/B/E')) 6469 6470@Issues(4323) 6471def bump_below_tree_conflict(sbox): 6472 "tree conflicts should be skipped during update" 6473 6474 sbox.build() 6475 wc_dir = sbox.wc_dir 6476 6477 svntest.actions.run_and_verify_svn(None, [], 6478 'rm', sbox.repo_url + '/A/B', 6479 '-m', '') 6480 6481 sbox.simple_add_text('Q', 'q') 6482 sbox.simple_commit() 6483 sbox.simple_add_text('R', 'r') 6484 sbox.simple_commit() 6485 6486 sbox.simple_update(revision='1') 6487 6488 sbox.simple_rm('A') 6489 6490 expected_output = svntest.wc.State(wc_dir, { 6491 'A' : Item(status=' ', treeconflict='C'), # The real TC 6492 'A/B' : Item(status=' ', treeconflict='D'), # Shadowed delete 6493 }) 6494 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 6495 6496 expected_status.tweak('A', status='D ', treeconflict='C', wc_rev='2') 6497 expected_status.tweak('A/D', 'A/D/G', 'A/D/G/rho', 'A/D/G/tau', 'A/D/G/pi', 6498 'A/D/H', 'A/D/H/omega', 'A/D/H/chi', 'A/D/H/psi', 6499 'A/D/gamma', 'A/mu', 'A/C', status='D ') 6500 6501 expected_status.remove('A/B', 'A/B/lambda', 'A/B/E', 'A/B/E/alpha', 6502 'A/B/E/beta', 'A/B/F') 6503 6504 svntest.actions.run_and_verify_update(wc_dir, 6505 expected_output, 6506 None, 6507 expected_status, 6508 [], False, 6509 '-r', '2', wc_dir) 6510 6511 # A is tree conflicted, so an update of A/D should be a skip/no-op. 6512 expected_output = svntest.wc.State(wc_dir, { 6513 'A/D' : Item(verb='Skipped'), 6514 }) 6515 svntest.actions.run_and_verify_update(wc_dir, 6516 expected_output, 6517 None, 6518 expected_status, 6519 [], False, 6520 sbox.ospath('A/D')) 6521 6522 # A is tree conflicted, so an update of A/D/G should be a skip/no-op. 6523 expected_output = svntest.wc.State(wc_dir, { 6524 'A/D/G' : Item(verb='Skipped'), 6525 }) 6526 svntest.actions.run_and_verify_update(wc_dir, 6527 expected_output, 6528 None, 6529 expected_status, 6530 [], False, 6531 sbox.ospath('A/D/G')) 6532 6533@Issues(4111) 6534def update_child_below_add(sbox): 6535 "update child below added tree" 6536 6537 sbox.build(read_only = True) 6538 wc_dir = sbox.wc_dir 6539 6540 sbox.simple_update('A/B', 0) 6541 e_path = sbox.ospath('A/B/E') 6542 6543 # Update skips and errors on A/B/E because A/B has a not-present BASE node. 6544 expected_output = ["Skipped '"+e_path+"'\n"] 6545 expected_err = "svn: E155007: " 6546 expected_status = svntest.actions.get_virginal_state(wc_dir, 1) 6547 expected_status.remove('A/B', 'A/B/E', 'A/B/E/alpha', 'A/B/E/beta', 6548 'A/B/F', 'A/B/lambda') 6549 svntest.actions.run_and_verify_svn(expected_output, 6550 expected_err, 6551 'update', e_path) 6552 svntest.actions.run_and_verify_status(wc_dir, expected_status) 6553 6554 6555 # Add working nodes over A/B 6556 sbox.simple_mkdir('A/B') 6557 sbox.simple_mkdir('A/B/E') 6558 sbox.simple_add_text('the new alpha', 'A/B/E/alpha') 6559 6560 expected_status.add({ 6561 'A/B' : Item(status='A ', wc_rev='-'), 6562 'A/B/E' : Item(status='A ', wc_rev='-'), 6563 'A/B/E/alpha' : Item(status='A ', wc_rev='-'), 6564 }) 6565 expected_output = svntest.wc.State(wc_dir, { 6566 'A/B/E' : Item(verb='Skipped'), 6567 }) 6568 # Update should still skip A/B/E 6569 svntest.actions.run_and_verify_update(wc_dir, 6570 expected_output, 6571 None, 6572 expected_status, 6573 [], False, 6574 sbox.ospath('A/B/E')) 6575 6576def update_conflict_details(sbox): 6577 "update conflict details" 6578 6579 sbox.build() 6580 wc_dir = sbox.wc_dir 6581 6582 sbox.simple_append('A/B/E/new', 'new\n') 6583 sbox.simple_add('A/B/E/new') 6584 sbox.simple_append('A/B/E/alpha', '\nextra\nlines\n') 6585 sbox.simple_rm('A/B/E/beta', 'A/B/F') 6586 sbox.simple_propset('key', 'VAL', 'A/B/E', 'A/B') 6587 sbox.simple_mkdir('A/B/E/new-dir1') 6588 sbox.simple_mkdir('A/B/E/new-dir2') 6589 sbox.simple_mkdir('A/B/E/new-dir3') 6590 sbox.simple_rm('A/B/lambda') 6591 sbox.simple_mkdir('A/B/lambda') 6592 sbox.simple_commit() 6593 6594 sbox.simple_update('', 1) 6595 6596 sbox.simple_propset('key', 'vAl', 'A/B') 6597 sbox.simple_move('A/B/E/beta', 'beta') 6598 sbox.simple_propset('a', 'b', 'A/B/F', 'A/B/lambda') 6599 sbox.simple_append('A/B/E/alpha', 'other\nnew\nlines') 6600 sbox.simple_mkdir('A/B/E/new') 6601 sbox.simple_mkdir('A/B/E/new-dir1') 6602 sbox.simple_append('A/B/E/new-dir2', 'something') 6603 sbox.simple_append('A/B/E/new-dir3', 'something') 6604 sbox.simple_add('A/B/E/new-dir3') 6605 6606 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 6607 expected_status.add({ 6608 'A/B/E/new' : Item(status='R ', treeconflict='C', wc_rev='2'), 6609 'A/B/E/new-dir2' : Item(status='D ', treeconflict='C', wc_rev='2'), 6610 'A/B/E/new-dir3' : Item(status='R ', treeconflict='C', wc_rev='2'), 6611 'A/B/E/new-dir1' : Item(status=' ', wc_rev='2'), 6612 'A/C' : Item(status=' ', wc_rev='2'), 6613 'iota' : Item(status=' ', wc_rev='2'), 6614 'beta' : Item(status='A ', copied='+', wc_rev='-') 6615 }) 6616 expected_status.tweak('A/B', status=' C', wc_rev='2') 6617 expected_status.tweak('A/B/E/alpha', status='C ', wc_rev='2') 6618 expected_status.tweak('A/B/E/beta', status='! ', treeconflict='C', wc_rev=None) 6619 expected_status.tweak('A/B/F', status='A ', copied='+', treeconflict='C', wc_rev='-') 6620 expected_status.tweak('A/B/lambda', status='RM', copied='+', treeconflict='C', wc_rev='-') 6621 expected_status.tweak('A/mu', status=' ', wc_rev='2') 6622 expected_output = svntest.wc.State(wc_dir, { 6623 'A/B' : Item(status=' C'), 6624 'A/B/E' : Item(status=' U'), 6625 'A/B/E/new' : Item(status=' ', treeconflict='C'), 6626 'A/B/E/beta' : Item(status=' ', treeconflict='C'), 6627 'A/B/E/alpha' : Item(status='C '), 6628 'A/B/E/new-dir2' : Item(status=' ', treeconflict='C'), 6629 'A/B/E/new-dir3' : Item(status=' ', treeconflict='C'), 6630 'A/B/E/new-dir1' : Item(status='E '), 6631 'A/B/F' : Item(status=' ', treeconflict='C'), 6632 # ### 2 tree conflict reports; one for delete; one for add... 6633 'A/B/lambda' : Item(status=' ', treeconflict='A', 6634 prev_status=' ', prev_treeconflict='C'), 6635 }) 6636 svntest.actions.run_and_verify_update(wc_dir, expected_output, 6637 None, expected_status, 6638 [], False, 6639 '--adds-as-modification', wc_dir) 6640 6641 # Update can't pass source as none at a specific URL@revision, 6642 # because it doesn't know... the working copy could be mixed 6643 # revision or may have excluded parts... 6644 expected_info = [ 6645 { 6646 "Path" : re.escape(sbox.ospath('A/B')), 6647 6648 "Conflicted Properties" : "key", 6649 "Conflict Details": re.escape( 6650 'incoming dir edit upon update' + 6651 ' Source left: (dir) ^/A/B@1' + 6652 ' Source right: (dir) ^/A/B@2') 6653 }, 6654 { 6655 "Path" : re.escape(sbox.ospath('A/B/E')), 6656 }, 6657 { 6658 "Path" : re.escape(sbox.ospath('A/B/E/alpha')), 6659 "Conflict Previous Base File" : '.*alpha.*', 6660 "Conflict Previous Working File" : '.*alpha.*', 6661 "Conflict Current Base File": '.*alpha.*', 6662 "Conflict Details": re.escape( 6663 'incoming file edit upon update' + 6664 ' Source left: (file) ^/A/B/E/alpha@1' + 6665 ' Source right: (file) ^/A/B/E/alpha@2') 6666 }, 6667 { 6668 "Path" : re.escape(sbox.ospath('A/B/E/beta')), 6669 "Tree conflict": re.escape( 6670 'local file moved away, incoming file delete or move upon update' + 6671 ' Source left: (file) ^/A/B/E/beta@1' + 6672 ' Source right: (none) ^/A/B/E/beta@2') 6673 }, 6674 { 6675 "Path" : re.escape(sbox.ospath('A/B/E/new')), 6676 "Tree conflict": re.escape( 6677 'local dir add, incoming file add upon update' + 6678 ' Source left: (none)' + 6679 ' Source right: (file) ^/A/B/E/new@2') 6680 }, 6681 { 6682 "Path" : re.escape(sbox.ospath('A/B/E/new-dir1')), 6683 # No tree conflict. Existing directory taken over 6684 }, 6685 { 6686 "Path" : re.escape(sbox.ospath('A/B/E/new-dir2')), 6687 "Tree conflict": re.escape( 6688 'local file unversioned, incoming dir add upon update' + 6689 ' Source left: (none)' + 6690 ' Source right: (dir) ^/A/B/E/new-dir2@2') 6691 }, 6692 { 6693 "Path" : re.escape(sbox.ospath('A/B/E/new-dir3')), 6694 "Tree conflict": re.escape( 6695 'local file add, incoming dir add upon update' + 6696 ' Source left: (none)' + 6697 ' Source right: (dir) ^/A/B/E/new-dir3@2') 6698 }, 6699 { 6700 "Path" : re.escape(sbox.ospath('A/B/F')), 6701 "Tree conflict": re.escape( 6702 'local dir edit, incoming dir delete or move upon update' + 6703 ' Source left: (dir) ^/A/B/F@1' + 6704 ' Source right: (none) ^/A/B/F@2') 6705 }, 6706 { 6707 "Path" : re.escape(sbox.ospath('A/B/lambda')), 6708 "Tree conflict": re.escape( 6709 'local file edit, incoming replace with dir upon update' + 6710 ' Source left: (file) ^/A/B/lambda@1' + 6711 ' Source right: (dir) ^/A/B/lambda@2') 6712 }, 6713 ] 6714 6715 svntest.actions.run_and_verify_info(expected_info, sbox.ospath('A/B'), 6716 '--depth', 'infinity') 6717 6718# Keywords should be updated in local file even if text change is shortcut 6719# (due to the local change being the same as the incoming change, for example). 6720@XFail() 6721@Issue(4585) 6722def update_keywords_on_shortcut(sbox): 6723 "update_keywords_on_shortcut" 6724 6725 sbox.build() 6726 wc_dir = sbox.wc_dir 6727 6728 # Start with a file with keywords expanded 6729 mu_path = sbox.ospath('A/mu') 6730 svntest.main.file_append(mu_path, '$LastChangedRevision$\n') 6731 svntest.main.run_svn(None, 'ps', 'svn:keywords', 'LastChangedRevision', mu_path) 6732 sbox.simple_commit('A/mu') 6733 6734 # Modify the text, and commit 6735 svntest.main.file_append(mu_path, 'New line.\n') 6736 sbox.simple_commit('A/mu') 6737 6738 # Update back to the previous revision 6739 sbox.simple_update('A/mu', 2) 6740 6741 # Make the same change again locally 6742 svntest.main.file_append(mu_path, 'New line.\n') 6743 6744 # Update, so that merging the text change is a short-cut merge 6745 text_before_up = open(sbox.ospath('A/mu'), 'r').readlines() 6746 sbox.simple_update('A/mu') 6747 text_after_up = open(sbox.ospath('A/mu'), 'r').readlines() 6748 6749 # Check the keywords have been updated 6750 if not any(['$LastChangedRevision: 2 $' in line 6751 for line in text_before_up]): 6752 raise svntest.Failure("keyword not as expected in test set-up phase") 6753 if not any(['$LastChangedRevision: 3 $' in line 6754 for line in text_after_up]): 6755 raise svntest.Failure("update did not update the LastChangedRevision keyword") 6756 6757def update_add_conflicted_deep(sbox): 6758 "deep add conflicted" 6759 6760 sbox.build() 6761 repo_url = sbox.repo_url 6762 6763 svntest.actions.run_and_verify_svnmucc( 6764 None, [], '-U', repo_url, '-m', '', 6765 'mkdir', 'A/z', 6766 'mkdir', 'A/z/z', 6767 'mkdir', 'A/z/z/z') 6768 6769 svntest.actions.run_and_verify_svnmucc( 6770 None, [], '-U', repo_url, '-m', '', 6771 'rm', 'A/z', 6772 'mkdir', 'A/z', 6773 'mkdir', 'A/z/z', 6774 'mkdir', 'A/z/z/z') 6775 6776 sbox.simple_append('A/z', 'A/z') 6777 sbox.simple_add('A/z') 6778 sbox.simple_update('A', 2) 6779 # This final update used to segfault using 1.9.0 and 1.9.1 6780 sbox.simple_update('A/z/z', 3) 6781 6782def missing_tmp_update(sbox): 6783 "missing tmp update caused segfault" 6784 6785 sbox.build(read_only = True) 6786 wc_dir = sbox.wc_dir 6787 svntest.actions.run_and_verify_update(wc_dir, None, None, None, [], False, 6788 wc_dir, '--set-depth', 'empty') 6789 6790 os.rmdir(sbox.ospath(svntest.main.get_admin_name() + '/tmp')) 6791 6792 svntest.actions.run_and_verify_svn(None, '.*Unable to create.*', 6793 'up', wc_dir, '--set-depth', 'infinity') 6794 6795 # This re-creates .svn/tmp as a side-effect. 6796 svntest.actions.run_and_verify_svn(None, [], 'cleanup', 6797 '--vacuum-pristines', wc_dir) 6798 6799 svntest.actions.run_and_verify_update(wc_dir, None, None, None, [], False, 6800 wc_dir, '--set-depth', 'infinity') 6801 6802def update_delete_switched(sbox): 6803 "update delete switched" 6804 6805 sbox.build(read_only = True) 6806 wc_dir = sbox.wc_dir 6807 6808 svntest.actions.run_and_verify_switch(wc_dir, sbox.ospath('A/B/E'), 6809 sbox.repo_url + '/A/D/G', 6810 None, None, None, [], False, 6811 '--ignore-ancestry') 6812 6813 # Introduce some change somewhere... 6814 sbox.simple_propset('A', 'A', 'A') 6815 6816 expected_status = svntest.wc.State(wc_dir, { 6817 '' : Item(status=' ', wc_rev='1'), 6818 'A' : Item(status='A ', copied='+', treeconflict='C', wc_rev='-'), 6819 'A/B' : Item(status=' ', copied='+', wc_rev='-'), 6820 'A/B/E' : Item(status='A ', copied='+', wc_rev='-'), 6821 'A/B/E/rho' : Item(status=' ', copied='+', wc_rev='-'), 6822 'A/B/E/pi' : Item(status=' ', copied='+', wc_rev='-'), 6823 'A/B/E/tau' : Item(status=' ', copied='+', wc_rev='-'), 6824 'A/B/lambda' : Item(status=' ', copied='+', wc_rev='-'), 6825 'A/B/F' : Item(status=' ', copied='+', wc_rev='-'), 6826 'A/D' : Item(status=' ', copied='+', wc_rev='-'), 6827 'A/D/G' : Item(status=' ', copied='+', wc_rev='-'), 6828 'A/D/G/pi' : Item(status=' ', copied='+', wc_rev='-'), 6829 'A/D/G/tau' : Item(status=' ', copied='+', wc_rev='-'), 6830 'A/D/G/rho' : Item(status=' ', copied='+', wc_rev='-'), 6831 'A/D/gamma' : Item(status=' ', copied='+', wc_rev='-'), 6832 'A/D/H' : Item(status=' ', copied='+', wc_rev='-'), 6833 'A/D/H/omega' : Item(status=' ', copied='+', wc_rev='-'), 6834 'A/D/H/psi' : Item(status=' ', copied='+', wc_rev='-'), 6835 'A/D/H/chi' : Item(status=' ', copied='+', wc_rev='-'), 6836 'A/mu' : Item(status=' ', copied='+', wc_rev='-'), 6837 'A/C' : Item(status=' ', copied='+', wc_rev='-'), 6838 'iota' : Item(status=' ', wc_rev='1'), 6839 }) 6840 svntest.actions.run_and_verify_update(wc_dir, None, None, expected_status, 6841 [], False, sbox.ospath('A'), '-r', 0) 6842 6843@XFail() 6844def update_add_missing_local_add(sbox): 6845 "update adds missing local addition" 6846 6847 sbox.build(read_only=True) 6848 6849 # Note that updating 'A' to r0 doesn't reproduce this issue... 6850 sbox.simple_update('', revision='0') 6851 sbox.simple_mkdir('A') 6852 sbox.simple_add_text('mumumu', 'A/mu') 6853 os.unlink(sbox.ospath('A/mu')) 6854 os.rmdir(sbox.ospath('A')) 6855 6856 sbox.simple_update() 6857 6858# Verify that deleting an unmodified directory leaves behind any unversioned 6859# items on disk 6860def update_keeps_unversioned_items_in_deleted_dir(sbox): 6861 "update keeps unversioned items in deleted dir" 6862 sbox.build() 6863 wc_dir = sbox.wc_dir 6864 6865 sbox.simple_rm('A/D/G') 6866 sbox.simple_commit() 6867 6868 sbox.simple_update('', revision='1') 6869 6870 os.mkdir(sbox.ospath('A/D/G/unversioned-dir')) 6871 svntest.main.file_write(sbox.ospath('A/D/G/unversioned.txt'), 6872 'unversioned file', 'wb') 6873 6874 expected_output = svntest.wc.State(wc_dir, { 6875 'A/D/G' : Item(status='D '), 6876 }) 6877 6878 expected_disk = svntest.main.greek_state.copy() 6879 # The unversioned items should be left behind on disk 6880 expected_disk.add({ 6881 'A/D/G/unversioned-dir' : Item(), 6882 'A/D/G/unversioned.txt' : Item('unversioned file'), 6883 }) 6884 expected_disk.remove('A/D/G/pi') 6885 expected_disk.remove('A/D/G/rho') 6886 expected_disk.remove('A/D/G/tau') 6887 6888 expected_status = svntest.actions.get_virginal_state(wc_dir, 2) 6889 expected_status.remove('A/D/G') 6890 expected_status.remove('A/D/G/pi') 6891 expected_status.remove('A/D/G/rho') 6892 expected_status.remove('A/D/G/tau') 6893 6894 svntest.actions.run_and_verify_update(wc_dir, 6895 expected_output, 6896 expected_disk, 6897 expected_status, 6898 [], True) 6899 6900####################################################################### 6901# Run the tests 6902 6903 6904# list all tests here, starting with None: 6905test_list = [ None, 6906 update_binary_file, 6907 update_binary_file_2, 6908 update_ignores_added, 6909 update_to_rev_zero, 6910 receive_overlapping_same_change, 6911 update_to_resolve_text_conflicts, 6912 update_delete_modified_files, 6913 update_after_add_rm_deleted, 6914 update_missing, 6915 update_replace_dir, 6916 update_single_file, 6917 prop_update_on_scheduled_delete, 6918 update_receive_illegal_name, 6919 update_deleted_missing_dir, 6920 another_hudson_problem, 6921 update_deleted_targets, 6922 new_dir_with_spaces, 6923 non_recursive_update, 6924 checkout_empty_dir, 6925 update_to_deletion, 6926 update_deletion_inside_out, 6927 update_schedule_add_dir, 6928 update_to_future_add, 6929 obstructed_update_alters_wc_props, 6930 update_xml_unsafe_dir, 6931 conflict_markers_matching_eol, 6932 update_eolstyle_handling, 6933 update_copy_of_old_rev, 6934 forced_update, 6935 forced_update_failures, 6936 update_wc_on_windows_drive, 6937 update_wc_with_replaced_file, 6938 update_with_obstructing_additions, 6939 update_conflicted, 6940 mergeinfo_update_elision, 6941 update_copied_from_replaced_and_changed, 6942 update_copied_and_deleted_prop, 6943 update_accept_conflicts, 6944 update_uuid_changed, 6945 restarted_update_should_delete_dir_prop, 6946 tree_conflicts_on_update_1_1, 6947 tree_conflicts_on_update_1_2, 6948 tree_conflicts_on_update_2_1, 6949 tree_conflicts_on_update_2_2, 6950 tree_conflicts_on_update_2_3, 6951 tree_conflicts_on_update_3, 6952 tree_conflict_uc1_update_deleted_tree, 6953 tree_conflict_uc2_schedule_re_add, 6954 set_deep_depth_on_target_with_shallow_children, 6955 update_wc_of_dir_to_rev_not_containing_this_dir, 6956 update_empty_hides_entries, 6957 mergeinfo_updates_merge_with_local_mods, 6958 update_with_excluded_subdir, 6959 update_with_file_lock_and_keywords_property_set, 6960 update_nonexistent_child_of_copy, 6961 revive_children_of_copy, 6962 skip_access_denied, 6963 update_to_HEAD_plus_1, 6964 update_moved_dir_leaf_del, 6965 update_moved_dir_edited_leaf_del, 6966 update_moved_dir_file_add, 6967 update_moved_dir_dir_add, 6968 update_moved_dir_file_move, 6969 update_binary_file_3, 6970 update_move_text_mod, 6971 update_nested_move_text_mod, 6972 update_with_parents_and_exclude, 6973 update_edit_delete_obstruction, 6974 update_deleted, 6975 break_moved_dir_edited_leaf_del, 6976 break_moved_replaced_dir, 6977 update_removes_switched, 6978 incomplete_overcomplete, 6979 update_swapped_depth_dirs, 6980 move_update_props, 6981 windows_update_backslash, 6982 update_moved_away, 6983 bump_below_tree_conflict, 6984 update_child_below_add, 6985 update_conflict_details, 6986 update_keywords_on_shortcut, 6987 update_add_conflicted_deep, 6988 missing_tmp_update, 6989 update_delete_switched, 6990 update_add_missing_local_add, 6991 update_keeps_unversioned_items_in_deleted_dir, 6992 ] 6993 6994if __name__ == '__main__': 6995 svntest.main.run_tests(test_list) 6996 # NOTREACHED 6997 6998 6999### End of file. 7000