3 # update_tests.py: testing update cases.
5 # Subversion is a tool for revision control.
6 # See http://subversion.tigris.org for more information.
8 # ====================================================================
9 # Copyright (c) 2000-2007 CollabNet. All rights reserved.
11 # This software is licensed as described in the file COPYING, which
12 # you should have received as part of this distribution. The terms
13 # are also available at http://subversion.tigris.org/license-1.html.
14 # If newer versions of this license are posted there, you may use a
15 # newer version instead, at your option.
17 ######################################################################
24 from svntest
import wc
27 Skip
= svntest
.testcase
.Skip
28 SkipUnless
= svntest
.testcase
.SkipUnless
29 XFail
= svntest
.testcase
.XFail
30 Item
= svntest
.wc
.StateItem
32 from svntest
.main
import SVN_PROP_MERGE_INFO
, server_sends_copyfrom_on_update
34 ######################################################################
37 # Each test must return on success or raise on failure.
40 #----------------------------------------------------------------------
42 # Helper for update_binary_file() test -- a custom singleton handler.
43 def detect_extra_files(node
, extra_files
):
44 """NODE has been discovered as an extra file on disk. Verify that
45 it matches one of the regular expressions in the EXTRA_FILES list of
46 lists, and that its contents matches the second part of the list
47 item. If it matches, remove the match from the list. If it doesn't
48 match, raise an exception."""
50 # Baton is of the form:
52 # [ [wc_dir, pattern, contents],
53 # [wc_dir, pattern, contents], ... ]
55 for fdata
in extra_files
:
61 match_obj
= re
.match(pattern
, node
.name
)
66 real_contents
= svntest
.main
.file_read(os
.path
.join(wc_dir
, node
.path
))
67 if real_contents
== contents
:
68 extra_files
.pop(extra_files
.index(fdata
)) # delete pattern from list
71 print "Found unexpected object:", node
.name
72 raise svntest
.tree
.SVNTreeUnequal
76 def update_binary_file(sbox
):
77 "update a locally-modified binary file"
82 # Add a binary file to the project.
83 theta_contents
= svntest
.main
.file_read(
84 os
.path
.join(sys
.path
[0], "theta.bin"), 'rb')
85 # Write PNG file data into 'A/theta'.
86 theta_path
= os
.path
.join(wc_dir
, 'A', 'theta')
87 svntest
.main
.file_write(theta_path
, theta_contents
, 'wb')
89 svntest
.main
.run_svn(None, 'add', theta_path
)
91 # Created expected output tree for 'svn ci'
92 expected_output
= svntest
.wc
.State(wc_dir
, {
93 'A/theta' : Item(verb
='Adding (bin)'),
96 # Create expected status tree
97 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
99 'A/theta' : Item(status
=' ', wc_rev
=2),
102 # Commit the new binary file, creating revision 2.
103 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
104 expected_status
, None,
105 None, None, None, None, wc_dir
)
107 # Make a backup copy of the working copy.
108 wc_backup
= sbox
.add_wc_path('backup')
109 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
110 theta_backup_path
= os
.path
.join(wc_backup
, 'A', 'theta')
112 # Make a change to the binary file in the original working copy
113 svntest
.main
.file_append(theta_path
, "revision 3 text")
114 theta_contents_r3
= theta_contents
+ "revision 3 text"
116 # Created expected output tree for 'svn ci'
117 expected_output
= svntest
.wc
.State(wc_dir
, {
118 'A/theta' : Item(verb
='Sending'),
121 # Create expected status tree
122 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
123 expected_status
.add({
124 'A/theta' : Item(status
=' ', wc_rev
=3),
127 # Commit original working copy again, creating revision 3.
128 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
129 expected_status
, None,
130 None, None, None, None, wc_dir
)
132 # Now start working in the backup working copy:
134 # Make a local mod to theta
135 svntest
.main
.file_append(theta_backup_path
, "extra theta text")
136 theta_contents_local
= theta_contents
+ "extra theta text"
138 # Create expected output tree for an update of wc_backup.
139 expected_output
= svntest
.wc
.State(wc_backup
, {
140 'A/theta' : Item(status
='C '),
143 # Create expected disk tree for the update --
144 # look! binary contents, and a binary property!
145 expected_disk
= svntest
.main
.greek_state
.copy()
147 'A/theta' : Item(theta_contents_local
,
148 props
={'svn:mime-type' : 'application/octet-stream'}),
151 # Create expected status tree for the update.
152 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 3)
153 expected_status
.add({
154 'A/theta' : Item(status
='C ', wc_rev
=3),
157 # Extra 'singleton' files we expect to exist after the update.
158 # In the case, the locally-modified binary file should be backed up
160 # This is a list of lists, of the form [ WC_DIR,
161 # [pattern, contents], ...]
162 extra_files
= [[wc_backup
, 'theta.*\.r2', theta_contents
],
163 [wc_backup
, 'theta.*\.r3', theta_contents_r3
]]
165 # Do the update and check the results in three ways. Pass our
166 # custom singleton handler to verify the .orig file; this handler
167 # will verify the existence (and contents) of both binary files
168 # after the update finishes.
169 svntest
.actions
.run_and_verify_update(wc_backup
,
174 detect_extra_files
, extra_files
,
177 # verify that the extra_files list is now empty.
178 if len(extra_files
) != 0:
179 print "Not all extra reject files have been accounted for:"
181 raise svntest
.Failure
183 #----------------------------------------------------------------------
185 def update_binary_file_2(sbox
):
186 "update to an old revision of a binary files"
191 # Suck up contents of a test .png file.
192 theta_contents
= svntest
.main
.file_read(
193 os
.path
.join(sys
.path
[0], "theta.bin"), 'rb')
195 # 102400 is svn_txdelta_window_size. We're going to make sure we
196 # have at least 102401 bytes of data in our second binary file (for
197 # no reason other than we have had problems in the past with getting
198 # svndiff data out of the repository for files > 102400 bytes).
199 # How? Well, we'll just keep doubling the binary contents of the
200 # original theta.png until we're big enough.
201 zeta_contents
= theta_contents
202 while(len(zeta_contents
) < 102401):
203 zeta_contents
= zeta_contents
+ zeta_contents
205 # Write our two files' contents out to disk, in A/theta and A/zeta.
206 theta_path
= os
.path
.join(wc_dir
, 'A', 'theta')
207 svntest
.main
.file_write(theta_path
, theta_contents
, 'wb')
208 zeta_path
= os
.path
.join(wc_dir
, 'A', 'zeta')
209 svntest
.main
.file_write(zeta_path
, zeta_contents
, 'wb')
211 # Now, `svn add' those two files.
212 svntest
.main
.run_svn(None, 'add', theta_path
, zeta_path
)
214 # Created expected output tree for 'svn ci'
215 expected_output
= svntest
.wc
.State(wc_dir
, {
216 'A/theta' : Item(verb
='Adding (bin)'),
217 'A/zeta' : Item(verb
='Adding (bin)'),
220 # Create expected status tree
221 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
222 expected_status
.add({
223 'A/theta' : Item(status
=' ', wc_rev
=2),
224 'A/zeta' : Item(status
=' ', wc_rev
=2),
227 # Commit the new binary filea, creating revision 2.
228 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
229 expected_status
, None,
230 None, None, None, None, wc_dir
)
232 # Make some mods to the binary files.
233 svntest
.main
.file_append(theta_path
, "foobar")
234 new_theta_contents
= theta_contents
+ "foobar"
235 svntest
.main
.file_append(zeta_path
, "foobar")
236 new_zeta_contents
= zeta_contents
+ "foobar"
238 # Created expected output tree for 'svn ci'
239 expected_output
= svntest
.wc
.State(wc_dir
, {
240 'A/theta' : Item(verb
='Sending'),
241 'A/zeta' : Item(verb
='Sending'),
244 # Create expected status tree
245 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
246 expected_status
.add({
247 'A/theta' : Item(status
=' ', wc_rev
=3),
248 'A/zeta' : Item(status
=' ', wc_rev
=3),
251 # Commit original working copy again, creating revision 3.
252 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
253 expected_status
, None,
254 None, None, None, None, wc_dir
)
256 # Create expected output tree for an update to rev 2.
257 expected_output
= svntest
.wc
.State(wc_dir
, {
258 'A/theta' : Item(status
='U '),
259 'A/zeta' : Item(status
='U '),
262 # Create expected disk tree for the update --
263 # look! binary contents, and a binary property!
264 expected_disk
= svntest
.main
.greek_state
.copy()
266 'A/theta' : Item(theta_contents
,
267 props
={'svn:mime-type' : 'application/octet-stream'}),
268 'A/zeta' : Item(zeta_contents
,
269 props
={'svn:mime-type' : 'application/octet-stream'}),
272 # Create expected status tree for the update.
273 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
274 expected_status
.add({
275 'A/theta' : Item(status
=' ', wc_rev
=2),
276 'A/zeta' : Item(status
=' ', wc_rev
=2),
279 # Do an update from revision 2 and make sure that our binary file
280 # gets reverted to its original contents.
281 svntest
.actions
.run_and_verify_update(wc_dir
,
290 #----------------------------------------------------------------------
292 def update_missing(sbox
):
293 "update missing items (by name) in working copy"
298 # Remove some files and dirs from the working copy.
299 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
300 rho_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'rho')
301 E_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E')
302 H_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H')
304 # remove two files to verify that they get restored
308 ### FIXME I think directories work because they generate 'A'
309 ### feedback, is this the correct feedback?
310 svntest
.main
.safe_rmtree(E_path
)
311 svntest
.main
.safe_rmtree(H_path
)
313 # Create expected output tree for an update of the missing items by name
314 expected_output
= svntest
.wc
.State(wc_dir
, {
315 'A/mu' : Item(verb
='Restored'),
316 'A/D/G/rho' : Item(verb
='Restored'),
317 'A/B/E' : Item(status
='A '),
318 'A/B/E/alpha' : Item(status
='A '),
319 'A/B/E/beta' : Item(status
='A '),
320 'A/D/H' : Item(status
='A '),
321 'A/D/H/chi' : Item(status
='A '),
322 'A/D/H/omega' : Item(status
='A '),
323 'A/D/H/psi' : Item(status
='A '),
326 # Create expected disk tree for the update.
327 expected_disk
= svntest
.main
.greek_state
.copy()
329 # Create expected status tree for the update.
330 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
332 # Do the update and check the results in three ways.
333 svntest
.actions
.run_and_verify_update(wc_dir
,
337 None, None, None, None, None, 0,
341 #----------------------------------------------------------------------
343 def update_ignores_added(sbox
):
344 "update should not munge adds or replaces"
349 # Commit something so there's actually a new revision to update to.
350 rho_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'rho')
351 svntest
.main
.file_append(rho_path
, "More stuff in rho.\n")
352 svntest
.main
.run_svn(None,
353 'ci', '-m', 'log msg', rho_path
)
355 # Create a new file, 'zeta', and schedule it for addition.
356 zeta_path
= os
.path
.join(wc_dir
, 'A', 'B', 'zeta')
357 svntest
.main
.file_append(zeta_path
, "This is the file 'zeta'.\n")
358 svntest
.main
.run_svn(None, 'add', zeta_path
)
360 # Schedule another file, say, 'gamma', for replacement.
361 gamma_path
= os
.path
.join(wc_dir
, 'A', 'D', 'gamma')
362 svntest
.main
.run_svn(None, 'delete', gamma_path
)
363 svntest
.main
.file_append(gamma_path
, "This is a new 'gamma' now.\n")
364 svntest
.main
.run_svn(None, 'add', gamma_path
)
366 # Now update. "zeta at revision 0" should *not* be reported at all,
367 # so it should remain scheduled for addition at revision 0. gamma
368 # was scheduled for replacement, so it also should remain marked as
369 # such, and maintain its revision of 1.
371 # Create expected output tree for an update of the wc_backup.
372 expected_output
= svntest
.wc
.State(wc_dir
, { })
374 # Create expected disk tree for the update.
375 expected_disk
= svntest
.main
.greek_state
.copy()
377 'A/B/zeta' : Item("This is the file 'zeta'.\n"),
379 expected_disk
.tweak('A/D/gamma', contents
="This is a new 'gamma' now.\n")
380 expected_disk
.tweak('A/D/G/rho',
381 contents
="This is the file 'rho'.\nMore stuff in rho.\n")
383 # Create expected status tree for the update.
384 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
385 expected_status
.tweak('A/D/gamma', wc_rev
=1, status
='R ')
386 expected_status
.add({
387 'A/B/zeta' : Item(status
='A ', wc_rev
=0),
390 # Do the update and check the results in three ways.
391 svntest
.actions
.run_and_verify_update(wc_dir
,
397 #----------------------------------------------------------------------
399 def update_to_rev_zero(sbox
):
400 "update to revision 0"
405 iota_path
= os
.path
.join(wc_dir
, 'iota')
406 A_path
= os
.path
.join(wc_dir
, 'A')
408 # Create expected output tree for an update to rev 0
409 expected_output
= svntest
.wc
.State(wc_dir
, {
410 'iota' : Item(status
='D '),
411 'A' : Item(status
='D '),
414 # Create expected disk tree for the update to rev 0
415 expected_disk
= svntest
.wc
.State(wc_dir
, { })
417 # Do the update and check the results.
418 svntest
.actions
.run_and_verify_update(wc_dir
,
422 None, None, None, None, 0,
425 #----------------------------------------------------------------------
427 def receive_overlapping_same_change(sbox
):
428 "overlapping identical changes should not conflict"
430 ### (See http://subversion.tigris.org/issues/show_bug.cgi?id=682.)
432 ### How this test works:
434 ### Create working copy foo, modify foo/iota. Duplicate foo,
435 ### complete with locally modified iota, to bar. Now we should
444 ### Commit the change from foo, then update bar. The repository
445 ### change should get folded into bar/iota with no conflict, since
446 ### the two modifications are identical.
452 iota_path
= os
.path
.join(wc_dir
, 'iota')
453 svntest
.main
.file_append(iota_path
, "A change to iota.\n")
455 # Duplicate locally modified wc, giving us the "other" wc.
456 other_wc
= sbox
.add_wc_path('other')
457 svntest
.actions
.duplicate_dir(wc_dir
, other_wc
)
458 other_iota_path
= os
.path
.join(other_wc
, 'iota')
460 # Created expected output tree for 'svn ci'
461 expected_output
= svntest
.wc
.State(wc_dir
, {
462 'iota' : Item(verb
='Sending'),
465 # Create expected status tree
466 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
467 expected_status
.tweak('iota', wc_rev
=2)
469 # Commit the change, creating revision 2.
470 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
471 expected_status
, None,
472 None, None, None, None, wc_dir
)
474 # Expected output tree for update of other_wc.
475 expected_output
= svntest
.wc
.State(other_wc
, {
476 'iota' : Item(status
='G '),
479 # Expected disk tree for the update.
480 expected_disk
= svntest
.main
.greek_state
.copy()
481 expected_disk
.tweak('iota',
482 contents
="This is the file 'iota'.\nA change to iota.\n")
484 # Expected status tree for the update.
485 expected_status
= svntest
.actions
.get_virginal_state(other_wc
, 2)
487 # Do the update and check the results in three ways.
488 svntest
.actions
.run_and_verify_update(other_wc
,
493 #----------------------------------------------------------------------
495 def update_to_resolve_text_conflicts(sbox
):
496 "delete files and update to resolve text conflicts"
501 # Make a backup copy of the working copy
502 wc_backup
= sbox
.add_wc_path('backup')
503 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
505 # Make a couple of local mods to files which will be committed
506 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
507 rho_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'rho')
508 svntest
.main
.file_append(mu_path
, 'Original appended text for mu\n')
509 svntest
.main
.file_append(rho_path
, 'Original appended text for rho\n')
510 svntest
.main
.run_svn(None, 'propset', 'Kubla', 'Khan', rho_path
)
512 # Make a couple of local mods to files which will be conflicted
513 mu_path_backup
= os
.path
.join(wc_backup
, 'A', 'mu')
514 rho_path_backup
= os
.path
.join(wc_backup
, 'A', 'D', 'G', 'rho')
515 svntest
.main
.file_append(mu_path_backup
,
516 'Conflicting appended text for mu\n')
517 svntest
.main
.file_append(rho_path_backup
,
518 'Conflicting appended text for rho\n')
519 svntest
.main
.run_svn(None, 'propset', 'Kubla', 'Xanadu', rho_path_backup
)
521 # Created expected output tree for 'svn ci'
522 expected_output
= svntest
.wc
.State(wc_dir
, {
523 'A/mu' : Item(verb
='Sending'),
524 'A/D/G/rho' : Item(verb
='Sending'),
527 # Create expected status tree; all local revisions should be at 1,
528 # but mu and rho should be at revision 2.
529 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
530 expected_status
.tweak('A/mu', wc_rev
=2)
531 expected_status
.tweak('A/D/G/rho', wc_rev
=2, status
=' ')
534 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
535 expected_status
, None,
536 None, None, None, None, wc_dir
)
538 # Create expected output tree for an update of the wc_backup.
539 expected_output
= svntest
.wc
.State(wc_backup
, {
540 'A/mu' : Item(status
='C '),
541 'A/D/G/rho' : Item(status
='CC'),
544 # Create expected disk tree for the update.
545 expected_disk
= svntest
.main
.greek_state
.copy()
546 expected_disk
.tweak('A/mu',
547 contents
="\n".join(["This is the file 'mu'.",
549 "Conflicting appended text for mu",
551 "Original appended text for mu",
554 expected_disk
.tweak('A/D/G/rho',
555 contents
="\n".join(["This is the file 'rho'.",
557 "Conflicting appended text for rho",
559 "Original appended text for rho",
563 # Create expected status tree for the update.
564 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 2)
565 expected_status
.tweak('A/mu', status
='C ')
566 expected_status
.tweak('A/D/G/rho', status
='CC')
568 # "Extra" files that we expect to result from the conflicts.
569 # These are expressed as list of regexps. What a cool system! :-)
570 extra_files
= ['mu.*\.r1', 'mu.*\.r2', 'mu.*\.mine',
571 'rho.*\.r1', 'rho.*\.r2', 'rho.*\.mine', 'rho.*\.prej']
573 # Do the update and check the results in three ways.
574 # All "extra" files are passed to detect_conflict_files().
575 svntest
.actions
.run_and_verify_update(wc_backup
,
580 svntest
.tree
.detect_conflict_files
,
584 # verify that the extra_files list is now empty.
585 if len(extra_files
) != 0:
586 print "didn't get expected extra files"
587 raise svntest
.Failure
589 # remove the conflicting files to clear text conflict but not props conflict
590 os
.remove(mu_path_backup
)
591 os
.remove(rho_path_backup
)
593 # ### TODO: Can't get run_and_verify_update to work here :-( I get
594 # the error "Unequal Types: one Node is a file, the other is a
595 # directory". Use run_svn and then run_and_verify_status instead
596 stdout_lines
, stdout_lines
= svntest
.main
.run_svn(None, 'up', wc_backup
)
597 if len (stdout_lines
) > 0:
598 print "update 2 failed"
599 raise svntest
.Failure
601 # Create expected status tree
602 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 2)
603 expected_status
.tweak('A/D/G/rho', status
=' C')
605 svntest
.actions
.run_and_verify_status(wc_backup
, expected_status
)
607 #----------------------------------------------------------------------
609 def update_delete_modified_files(sbox
):
610 "update that deletes modified files"
616 alpha_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'alpha')
617 svntest
.actions
.run_and_verify_svn("Deleting alpha failed", None, [],
620 # Delete a directory containing files
621 G_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G')
622 svntest
.actions
.run_and_verify_svn("Deleting G failed", None, [],
626 svntest
.actions
.run_and_verify_svn("Committing deletes failed", None, [],
627 'ci', '-m', 'log msg', wc_dir
)
629 # ### Update before backdating to avoid obstructed update error for G
630 svntest
.actions
.run_and_verify_svn("Updating after commit failed", None, [],
633 # Backdate to restore deleted items
634 svntest
.actions
.run_and_verify_svn("Backdating failed", None, [],
635 'up', '-r', '1', wc_dir
)
637 # Modify the file to be deleted, and a file in the directory to be deleted
638 svntest
.main
.file_append(alpha_path
, 'appended alpha text\n')
639 pi_path
= os
.path
.join(G_path
, 'pi')
640 svntest
.main
.file_append(pi_path
, 'appended pi text\n')
642 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
643 expected_status
.tweak('A/B/E/alpha', 'A/D/G/pi', status
='M ')
645 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
647 # Now update to 'delete' modified files -- that is, remove them from
648 # version control, but leave them on disk. It used to be we would
649 # expect an 'obstructed update' error (see issue #1196), but
650 # nowadays we expect success (see issue #1806).
651 expected_output
= svntest
.wc
.State(wc_dir
, {
652 'A/B/E/alpha' : Item(status
='D '),
653 'A/D/G' : Item(status
='D '),
655 expected_disk
= svntest
.main
.greek_state
.copy()
656 expected_disk
.tweak('A/B/E/alpha',
658 "This is the file 'alpha'.\nappended alpha text\n")
659 expected_disk
.tweak('A/D/G/pi',
661 "This is the file 'pi'.\nappended pi text\n")
662 expected_disk
.remove('A/D/G/rho')
663 expected_disk
.remove('A/D/G/tau')
664 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
665 expected_status
.remove('A/B/E/alpha')
666 expected_status
.remove('A/D/G')
667 expected_status
.remove('A/D/G/pi')
668 expected_status
.remove('A/D/G/rho')
669 expected_status
.remove('A/D/G/tau')
670 svntest
.actions
.run_and_verify_update(wc_dir
,
676 #----------------------------------------------------------------------
678 # Issue 847. Doing an add followed by a remove for an item in state
679 # "deleted" caused the "deleted" state to get forgotten
681 def update_after_add_rm_deleted(sbox
):
682 "update after add/rm of deleted state"
687 # Delete a file and directory from WC
688 alpha_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'alpha')
689 F_path
= os
.path
.join(wc_dir
, 'A', 'B', 'F')
690 svntest
.actions
.run_and_verify_svn(None, None, [], 'rm', alpha_path
, F_path
)
693 expected_output
= svntest
.wc
.State(wc_dir
, {
694 'A/B/E/alpha' : Item(verb
='Deleting'),
695 'A/B/F' : Item(verb
='Deleting'),
697 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
698 expected_status
.remove('A/B/E/alpha')
699 expected_status
.remove('A/B/F')
700 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
701 expected_status
, None,
702 None, None, None, None, wc_dir
)
704 # alpha and F are now in state "deleted", next we add a new ones
705 svntest
.main
.file_append(alpha_path
, "new alpha")
706 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', alpha_path
)
708 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', F_path
)
710 # New alpha and F should be in add state A
711 expected_status
.add({
712 'A/B/E/alpha' : Item(status
='A ', wc_rev
=0),
713 'A/B/F' : Item(status
='A ', wc_rev
=0),
715 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
717 # Forced removal of new alpha and F must restore "deleted" state
719 svntest
.actions
.run_and_verify_svn(None, None, [], 'rm', '--force',
721 if os
.path
.exists(alpha_path
) or os
.path
.exists(F_path
):
722 raise svntest
.Failure
724 # "deleted" state is not visible in status
725 expected_status
.remove('A/B/E/alpha', 'A/B/F')
726 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
728 # Although parent dir is already at rev 1, the "deleted" state will cause
729 # alpha and F to be restored in the WC when updated to rev 1
730 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', '-r', '1', wc_dir
)
731 expected_status
.add({
732 'A/B/E/alpha' : Item(status
=' ', wc_rev
=1),
733 'A/B/F' : Item(status
=' ', wc_rev
=1),
735 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
737 #----------------------------------------------------------------------
739 # Issue 1591. Updating a working copy which contains local
740 # obstructions marks a directory as incomplete. Removal of the
741 # obstruction and subsequent update should clear the "incomplete"
744 def obstructed_update_alters_wc_props(sbox
):
745 "obstructed update alters WC properties"
750 # Create a new dir in the repo in prep for creating an obstruction.
751 #print "Adding dir to repo"
752 svntest
.actions
.run_and_verify_svn(None, None, [],
754 'prep for obstruction',
755 sbox
.repo_url
+ '/A/foo')
757 # Create an obstruction, a file in the WC with the same name as
758 # present in a newer rev of the repo.
759 #print "Creating obstruction"
760 obstruction_parent_path
= os
.path
.join(wc_dir
, 'A')
761 obstruction_path
= os
.path
.join(obstruction_parent_path
, 'foo')
762 svntest
.main
.file_append(obstruction_path
, 'an obstruction')
764 # Update the WC to that newer rev to trigger the obstruction.
766 expected_output
= svntest
.wc
.State(wc_dir
, {})
767 expected_disk
= svntest
.main
.greek_state
.copy()
768 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
769 error_re
= 'Failed to add directory.*object of the same name already exists'
770 svntest
.actions
.run_and_verify_update(wc_dir
,
776 # Remove the file which caused the obstruction.
777 #print "Removing obstruction"
778 os
.unlink(obstruction_path
)
780 # Update the -- now unobstructed -- WC again.
781 #print "Updating WC again"
782 expected_output
= svntest
.wc
.State(wc_dir
, {
783 'A/foo' : Item(status
='A '),
785 expected_disk
= svntest
.main
.greek_state
.copy()
789 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
790 expected_status
.add({
791 'A/foo' : Item(status
=' ', wc_rev
=2),
793 svntest
.actions
.run_and_verify_update(wc_dir
,
798 # The previously obstructed resource should now be in the WC.
799 if not os
.path
.isdir(obstruction_path
):
800 raise svntest
.Failure
802 #----------------------------------------------------------------------
805 def update_replace_dir(sbox
):
806 "update that replaces a directory"
812 F_path
= os
.path
.join(wc_dir
, 'A', 'B', 'F')
813 svntest
.actions
.run_and_verify_svn(None, None, [], 'rm', F_path
)
816 expected_output
= svntest
.wc
.State(wc_dir
, {
817 'A/B/F' : Item(verb
='Deleting'),
819 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
820 expected_status
.remove('A/B/F')
821 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
822 expected_status
, None,
823 None, None, None, None, wc_dir
)
825 # Add replacement directory
826 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', F_path
)
829 expected_output
= svntest
.wc
.State(wc_dir
, {
830 'A/B/F' : Item(verb
='Adding'),
832 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
833 expected_status
.tweak('A/B/F', wc_rev
=3)
834 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
835 expected_status
, None,
836 None, None, None, None, wc_dir
)
839 expected_output
= svntest
.wc
.State(wc_dir
, {
841 expected_disk
= svntest
.main
.greek_state
.copy()
842 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 3)
843 svntest
.actions
.run_and_verify_update(wc_dir
,
848 # Update to revision 1 replaces the directory
849 ### I can't get this to work :-(
850 #expected_output = svntest.wc.State(wc_dir, {
851 # 'A/B/F' : Item(verb='Adding'),
852 # 'A/B/F' : Item(verb='Deleting'),
854 #expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
855 #svntest.actions.run_and_verify_update(wc_dir,
859 # None, None, None, None, None, 0,
862 # Update to revision 1 replaces the directory
863 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', '-r', '1', wc_dir
)
864 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
865 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
867 #----------------------------------------------------------------------
869 def update_single_file(sbox
):
870 "update with explicit file target"
875 expected_disk
= svntest
.main
.greek_state
.copy()
877 # Make a local mod to a file which will be committed
878 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
879 svntest
.main
.file_append(mu_path
, '\nAppended text for mu')
882 expected_output
= svntest
.wc
.State(wc_dir
, {
883 'A/mu' : Item(verb
='Sending'),
885 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
886 expected_status
.tweak('A/mu', wc_rev
=2)
887 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
888 expected_status
, None,
889 None, None, None, None, wc_dir
)
891 # At one stage 'svn up file' failed with a parent lock error
892 was_cwd
= os
.getcwd()
893 os
.chdir(os
.path
.join(wc_dir
, 'A'))
895 ### Can't get run_and_verify_update to work having done the chdir.
896 svntest
.actions
.run_and_verify_svn("update failed", None, [],
897 'up', '-r', '1', 'mu')
900 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
901 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
903 #----------------------------------------------------------------------
904 def prop_update_on_scheduled_delete(sbox
):
905 "receive prop update to file scheduled for deletion"
910 other_wc
= sbox
.add_wc_path('other')
912 # Make the "other" working copy.
913 svntest
.actions
.duplicate_dir(wc_dir
, other_wc
)
915 iota_path
= os
.path
.join(wc_dir
, 'iota')
916 other_iota_path
= os
.path
.join(other_wc
, 'iota')
918 svntest
.main
.run_svn(None, 'propset', 'foo', 'bar', iota_path
)
920 # Created expected output tree for 'svn ci'
921 expected_output
= svntest
.wc
.State(wc_dir
, {
922 'iota' : Item(verb
='Sending'),
925 # Create expected status tree
926 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
927 expected_status
.tweak('iota', wc_rev
=2)
929 # Commit the change, creating revision 2.
930 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
931 expected_status
, None,
932 None, None, None, None, wc_dir
)
934 svntest
.main
.run_svn(None, 'rm', other_iota_path
)
936 # Expected output tree for update of other_wc.
937 expected_output
= svntest
.wc
.State(other_wc
, {
938 'iota' : Item(status
=' U'),
941 # Expected disk tree for the update.
942 expected_disk
= svntest
.main
.greek_state
.copy()
943 expected_disk
.remove('iota')
945 # Expected status tree for the update.
946 expected_status
= svntest
.actions
.get_virginal_state(other_wc
, 2)
947 expected_status
.tweak('iota', status
='D ')
949 # Do the update and check the results in three ways.
950 svntest
.actions
.run_and_verify_update(other_wc
,
955 #----------------------------------------------------------------------
957 def update_receive_illegal_name(sbox
):
958 "bail when receive a file or dir named .svn"
963 # This tests the revision 4334 fix for issue #1068.
965 legal_url
= sbox
.repo_url
+ '/A/D/G/svn'
966 illegal_url
= (sbox
.repo_url
967 + '/A/D/G/' + svntest
.main
.get_admin_name())
968 # Ha! The client doesn't allow us to mkdir a '.svn' but it does
969 # allow us to copy to a '.svn' so ...
970 svntest
.actions
.run_and_verify_svn(None, None, [],
971 'mkdir', '-m', 'log msg',
973 svntest
.actions
.run_and_verify_svn(None, None, [],
974 'mv', '-m', 'log msg',
975 legal_url
, illegal_url
)
977 # Do the update twice, both should fail. After the first failure
978 # the wc will be marked "incomplete".
980 out
, err
= svntest
.main
.run_svn(1, 'up', wc_dir
)
982 if line
.find("an unversioned directory of the same " \
983 "name already exists") != -1:
986 raise svntest
.Failure
988 # At one stage an obstructed update in an incomplete wc would leave
990 out
, err
= svntest
.main
.run_svnadmin('lstxns', sbox
.repo_dir
)
992 raise svntest
.Failure
994 #----------------------------------------------------------------------
996 def update_deleted_missing_dir(sbox
):
997 "update missing dir to rev in which it is absent"
1000 wc_dir
= sbox
.wc_dir
1002 E_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E')
1003 H_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H')
1005 # Create a new revision with directories deleted
1006 svntest
.main
.run_svn(None, 'rm', E_path
)
1007 svntest
.main
.run_svn(None, 'rm', H_path
)
1008 svntest
.main
.run_svn(None,
1009 'ci', '-m', 'log msg', E_path
, H_path
)
1011 # Update back to the old revision
1012 svntest
.main
.run_svn(None,
1013 'up', '-r', '1', wc_dir
)
1015 # Delete the directories from disk
1016 svntest
.main
.safe_rmtree(E_path
)
1017 svntest
.main
.safe_rmtree(H_path
)
1019 # Create expected output tree for an update of the missing items by name
1020 expected_output
= svntest
.wc
.State(wc_dir
, {
1021 'A/B/E' : Item(status
='D '),
1022 'A/D/H' : Item(status
='D '),
1025 # Create expected disk tree for the update.
1026 expected_disk
= svntest
.main
.greek_state
.copy()
1027 expected_disk
.remove('A/B/E', 'A/B/E/alpha', 'A/B/E/beta')
1028 expected_disk
.remove('A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi')
1030 # Create expected status tree for the update.
1031 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1032 expected_status
.remove('A/B/E', 'A/B/E/alpha', 'A/B/E/beta')
1033 expected_status
.remove('A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi')
1035 # Do the update, specifying the deleted paths explicitly.
1036 svntest
.actions
.run_and_verify_update(wc_dir
,
1040 None, None, None, None, None,
1041 0, "-r", "2", E_path
, H_path
)
1043 # Update back to the old revision again
1044 svntest
.main
.run_svn(None,
1045 'up', '-r', '1', wc_dir
)
1047 # Delete the directories from disk
1048 svntest
.main
.safe_rmtree(E_path
)
1049 svntest
.main
.safe_rmtree(H_path
)
1051 # This time we're updating the whole working copy
1052 expected_status
.tweak(wc_rev
=2)
1054 # Do the update, on the whole working copy this time
1055 svntest
.actions
.run_and_verify_update(wc_dir
,
1059 None, None, None, None, None,
1060 0, "-r", "2", wc_dir
)
1062 #----------------------------------------------------------------------
1064 # Issue 919. This test was written as a regression test for "item
1065 # should remain 'deleted' when an update deletes a sibling".
1066 def another_hudson_problem(sbox
):
1067 "another \"hudson\" problem: updates that delete"
1070 wc_dir
= sbox
.wc_dir
1072 # Delete/commit gamma thus making it 'deleted'
1073 gamma_path
= os
.path
.join(wc_dir
, 'A', 'D', 'gamma')
1074 svntest
.main
.run_svn(None, 'rm', gamma_path
)
1075 expected_output
= svntest
.wc
.State(wc_dir
, {
1076 'A/D/gamma' : Item(verb
='Deleting'),
1078 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1079 expected_status
.remove('A/D/gamma')
1080 svntest
.actions
.run_and_verify_commit(wc_dir
,
1083 None, None, None, None, None,
1086 # Delete directory G from the repository
1087 svntest
.actions
.run_and_verify_svn(None,
1088 ['\n', 'Committed revision 3.\n'], [],
1089 'rm', '-m', 'log msg',
1090 sbox
.repo_url
+ '/A/D/G')
1092 # Remove corresponding tree from working copy
1093 G_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G')
1094 svntest
.main
.safe_rmtree(G_path
)
1096 # Update missing directory to receive the delete, this should mark G
1097 # as 'deleted' and should not alter gamma's entry.
1099 # Sigh, I can't get run_and_verify_update to work (but not because
1100 # of issue 919 as far as I can tell)
1101 svntest
.actions
.run_and_verify_svn(None,
1103 'Updated to revision 3.\n'], [],
1106 # Both G and gamma should be 'deleted', update should produce no output
1107 expected_output
= svntest
.wc
.State(wc_dir
, { })
1108 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 3)
1109 expected_status
.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau',
1111 expected_disk
= svntest
.main
.greek_state
.copy()
1112 expected_disk
.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau',
1114 svntest
.actions
.run_and_verify_update(wc_dir
,
1119 #----------------------------------------------------------------------
1120 def update_deleted_targets(sbox
):
1121 "explicit update of deleted=true targets"
1124 wc_dir
= sbox
.wc_dir
1126 # Delete/commit thus creating 'deleted=true' entries
1127 gamma_path
= os
.path
.join(wc_dir
, 'A', 'D', 'gamma')
1128 F_path
= os
.path
.join(wc_dir
, 'A', 'B', 'F')
1129 svntest
.main
.run_svn(None, 'rm', gamma_path
, F_path
)
1130 expected_output
= svntest
.wc
.State(wc_dir
, {
1131 'A/D/gamma' : Item(verb
='Deleting'),
1132 'A/B/F' : Item(verb
='Deleting'),
1134 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1135 expected_status
.remove('A/D/gamma', 'A/B/F')
1136 svntest
.actions
.run_and_verify_commit(wc_dir
,
1139 None, None, None, None, None,
1142 # Explicit update must not remove the 'deleted=true' entries
1143 svntest
.actions
.run_and_verify_svn(None, ['At revision 2.\n'], [],
1144 'update', gamma_path
)
1145 svntest
.actions
.run_and_verify_svn(None, ['At revision 2.\n'], [],
1148 # Update to r1 to restore items, since the parent directory is already
1149 # at r1 this fails if the 'deleted=true' entries are missing (issue 2250)
1150 expected_output
= svntest
.wc
.State(wc_dir
, {
1151 'A/D/gamma' : Item(status
='A '),
1152 'A/B/F' : Item(status
='A '),
1154 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1155 expected_disk
= svntest
.main
.greek_state
.copy()
1156 svntest
.actions
.run_and_verify_update(wc_dir
,
1160 None, None, None, None, None, 0,
1165 #----------------------------------------------------------------------
1167 def new_dir_with_spaces(sbox
):
1168 "receive new dir with spaces in its name"
1171 wc_dir
= sbox
.wc_dir
1173 # Create a new directory ("spacey dir") directly in repository
1174 svntest
.actions
.run_and_verify_svn(None,
1175 ['\n', 'Committed revision 2.\n'], [],
1176 'mkdir', '-m', 'log msg',
1178 + '/A/spacey%20dir')
1180 # Update, and make sure ra_neon doesn't choke on the space.
1181 expected_output
= svntest
.wc
.State(wc_dir
, {
1182 'A/spacey dir' : Item(status
='A '),
1184 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
1185 expected_status
.add({
1186 'A/spacey dir' : Item(status
=' ', wc_rev
=2),
1188 expected_disk
= svntest
.main
.greek_state
.copy()
1190 'A/spacey dir' : Item(),
1193 svntest
.actions
.run_and_verify_update(wc_dir
,
1198 #----------------------------------------------------------------------
1200 def non_recursive_update(sbox
):
1201 "non-recursive update"
1204 wc_dir
= sbox
.wc_dir
1206 # Commit a change to A/mu and A/D/G/rho
1207 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
1208 rho_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'rho')
1209 svntest
.main
.file_append(mu_path
, "new")
1210 svntest
.main
.file_append(rho_path
, "new")
1211 expected_output
= svntest
.wc
.State(wc_dir
, {
1212 'A/mu' : Item(verb
='Sending'),
1213 'A/D/G/rho' : Item(verb
='Sending'),
1215 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1216 expected_status
.tweak('A/mu', 'A/D/G/rho', wc_rev
=2)
1217 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
1219 None, None, None, None, None,
1222 # Update back to revision 1
1223 expected_output
= svntest
.wc
.State(wc_dir
, {
1224 'A/mu' : Item(status
='U '),
1225 'A/D/G/rho' : Item(status
='U '),
1227 expected_disk
= svntest
.main
.greek_state
.copy()
1228 expected_status
.tweak('A/mu', 'A/D/G/rho', wc_rev
=1)
1229 svntest
.actions
.run_and_verify_update(wc_dir
, expected_output
,
1230 expected_disk
, expected_status
,
1231 None, None, None, None, None, 0,
1234 # Non-recursive update of A should change A/mu but not A/D/G/rho
1235 A_path
= os
.path
.join(wc_dir
, 'A')
1236 expected_output
= svntest
.wc
.State(wc_dir
, {
1237 'A/mu' : Item(status
='U '),
1239 expected_status
.tweak('A', 'A/mu', wc_rev
=2)
1240 expected_disk
.tweak('A/mu', contents
="This is the file 'mu'.\nnew")
1241 svntest
.actions
.run_and_verify_update(wc_dir
, expected_output
,
1242 expected_disk
, expected_status
,
1243 None, None, None, None, None, 0,
1246 #----------------------------------------------------------------------
1248 def checkout_empty_dir(sbox
):
1249 "check out an empty dir"
1250 # See issue #1472 -- checked out empty dir should not be marked as
1251 # incomplete ("!" in status).
1252 sbox
.build(create_wc
= False)
1253 wc_dir
= sbox
.wc_dir
1255 C_url
= sbox
.repo_url
+ '/A/C'
1257 svntest
.main
.safe_rmtree(wc_dir
)
1258 svntest
.actions
.run_and_verify_svn(None, None, [], 'checkout', C_url
, wc_dir
)
1260 svntest
.actions
.run_and_verify_svn(None, [], [], 'status', wc_dir
)
1263 #----------------------------------------------------------------------
1264 # Regression test for issue #919: "another ghudson bug". Basically, if
1265 # we fore- or back-date an item until it no longer exists, we were
1266 # completely removing the entry, rather than marking it 'deleted'
1267 # (which we now do.)
1269 def update_to_deletion(sbox
):
1270 "update target till it's gone, then get it back"
1273 wc_dir
= sbox
.wc_dir
1275 iota_path
= os
.path
.join(wc_dir
, 'iota')
1277 # Update iota to rev 0, so it gets removed.
1278 expected_output
= svntest
.wc
.State(wc_dir
, {
1279 'iota' : Item(status
='D '),
1281 expected_disk
= svntest
.main
.greek_state
.copy()
1282 expected_disk
.remove('iota')
1284 svntest
.actions
.run_and_verify_update(wc_dir
,
1288 None, None, None, None, 0,
1289 '-r', '0', iota_path
)
1291 # Update the wc root, so iota comes back.
1292 expected_output
= svntest
.wc
.State(wc_dir
, {
1293 'iota' : Item(status
='A '),
1295 expected_disk
= svntest
.main
.greek_state
.copy()
1297 svntest
.actions
.run_and_verify_update(wc_dir
,
1301 None, None, None, None, 0,
1305 #----------------------------------------------------------------------
1307 def update_deletion_inside_out(sbox
):
1308 "update child before parent of a deleted tree"
1311 wc_dir
= sbox
.wc_dir
1313 parent_path
= os
.path
.join(wc_dir
, 'A', 'B')
1314 child_path
= os
.path
.join(parent_path
, 'E') # Could be a file, doesn't matter
1316 # Delete the parent directory.
1317 svntest
.actions
.run_and_verify_svn(None, None, [],
1319 svntest
.actions
.run_and_verify_svn(None, None, [],
1320 'ci', '-m', '', wc_dir
)
1322 # Update back to r1.
1323 svntest
.actions
.run_and_verify_svn(None, None, [],
1324 'update', '-r', '1', wc_dir
)
1326 # Update just the child to r2.
1327 svntest
.actions
.run_and_verify_svn(None, None, [],
1328 'update', '-r', '2', child_path
)
1330 # Now try a normal update.
1331 expected_output
= svntest
.wc
.State(wc_dir
, {
1332 'A/B' : Item(status
='D '),
1334 expected_disk
= svntest
.main
.greek_state
.copy()
1335 expected_disk
.remove('A/B', 'A/B/lambda', 'A/B/F',
1336 'A/B/E', 'A/B/E/alpha', 'A/B/E/beta')
1338 svntest
.actions
.run_and_verify_update(wc_dir
,
1344 #----------------------------------------------------------------------
1345 # Regression test for issue #1793, whereby 'svn up dir' would delete
1346 # dir if schedule-add. Yikes.
1348 def update_schedule_add_dir(sbox
):
1349 "update a schedule-add directory"
1352 wc_dir
= sbox
.wc_dir
1354 # Delete directory A/D/G in the repository via immediate commit
1355 G_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G')
1356 G_url
= sbox
.repo_url
+ '/A/D/G'
1357 svntest
.actions
.run_and_verify_svn(None, None, [],
1358 'rm', G_url
, '-m', 'rev 2')
1360 # Update the wc to HEAD (r2)
1361 expected_output
= svntest
.wc
.State(wc_dir
, {
1362 'A/D/G' : Item(status
='D '),
1364 expected_disk
= svntest
.main
.greek_state
.copy()
1365 expected_disk
.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
1366 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
1367 expected_status
.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
1368 svntest
.actions
.run_and_verify_update(wc_dir
,
1373 # Do a URL->wc copy, creating a new schedule-add A/D/G.
1374 # (Standard procedure when trying to resurrect the directory.)
1375 D_path
= os
.path
.join(wc_dir
, 'A', 'D')
1376 svntest
.actions
.run_and_verify_svn("Copy error:", None, [],
1377 'cp', G_url
+ '@1', D_path
)
1379 # status should now show the dir scheduled for addition-with-history
1380 expected_status
.add({
1381 'A/D/G' : Item(status
='A ', copied
='+', wc_rev
='-'),
1382 'A/D/G/pi' : Item(status
=' ', copied
='+', wc_rev
='-'),
1383 'A/D/G/rho' : Item(status
=' ', copied
='+', wc_rev
='-'),
1384 'A/D/G/tau' : Item(status
=' ', copied
='+', wc_rev
='-'),
1386 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
1388 # Now update with the schedule-add dir as the target.
1389 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', G_path
)
1391 # The update should be a no-op, and the schedule-add directory
1392 # should still exist! 'svn status' shouldn't change at all.
1393 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
1396 #----------------------------------------------------------------------
1397 # Test updating items that do not exist in the current WC rev, but do
1398 # exist at some future revision.
1400 def update_to_future_add(sbox
):
1401 "update target that was added in a future rev"
1404 wc_dir
= sbox
.wc_dir
1406 # Update the entire WC to rev 0
1407 # Create expected output tree for an update to rev 0
1408 expected_output
= svntest
.wc
.State(wc_dir
, {
1409 'iota' : Item(status
='D '),
1410 'A' : Item(status
='D '),
1413 # Create expected disk tree for the update to rev 0
1414 expected_disk
= svntest
.wc
.State(wc_dir
, { })
1416 # Do the update and check the results.
1417 svntest
.actions
.run_and_verify_update(wc_dir
,
1421 None, None, None, None, 0,
1424 # Update iota to the current HEAD.
1425 iota_path
= os
.path
.join(wc_dir
, 'iota')
1426 expected_output
= svntest
.wc
.State(wc_dir
, {
1427 'iota' : Item(status
='A '),
1429 expected_disk
= svntest
.wc
.State('', {
1430 'iota' : Item("This is the file 'iota'.\n")
1433 svntest
.actions
.run_and_verify_update(wc_dir
,
1437 None, None, None, None, 0,
1440 # Now try updating the directory into the future
1441 A_path
= os
.path
.join(wc_dir
, 'A')
1443 expected_output
= svntest
.wc
.State(wc_dir
, {
1444 'A' : Item(status
='A '),
1445 'A/mu' : Item(status
='A '),
1446 'A/B' : Item(status
='A '),
1447 'A/B/lambda' : Item(status
='A '),
1448 'A/B/E' : Item(status
='A '),
1449 'A/B/E/alpha' : Item(status
='A '),
1450 'A/B/E/beta' : Item(status
='A '),
1451 'A/B/F' : Item(status
='A '),
1452 'A/C' : Item(status
='A '),
1453 'A/D' : Item(status
='A '),
1454 'A/D/gamma' : Item(status
='A '),
1455 'A/D/G' : Item(status
='A '),
1456 'A/D/G/pi' : Item(status
='A '),
1457 'A/D/G/rho' : Item(status
='A '),
1458 'A/D/G/tau' : Item(status
='A '),
1459 'A/D/H' : Item(status
='A '),
1460 'A/D/H/chi' : Item(status
='A '),
1461 'A/D/H/psi' : Item(status
='A '),
1462 'A/D/H/omega' : Item(status
='A ')
1464 expected_disk
= svntest
.main
.greek_state
.copy()
1466 svntest
.actions
.run_and_verify_update(wc_dir
,
1470 None, None, None, None, 0,
1473 #----------------------------------------------------------------------
1475 def nested_in_read_only(sbox
):
1476 "update a nested wc in a read-only wc"
1479 wc_dir
= sbox
.wc_dir
1481 # Delete/commit a file
1482 alpha_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'alpha')
1483 svntest
.actions
.run_and_verify_svn(None, None, [], 'rm', alpha_path
)
1484 expected_output
= svntest
.wc
.State(wc_dir
, {
1485 'A/B/E/alpha' : Item(verb
='Deleting'),
1487 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1488 expected_status
.remove('A/B/E/alpha')
1489 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
1490 expected_status
, None,
1491 None, None, None, None, wc_dir
)
1492 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
1493 expected_status
.tweak(wc_rev
=2)
1494 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
1496 # Delete/commit a directory that used to contain the deleted file
1497 B_path
= os
.path
.join(wc_dir
, 'A', 'B')
1498 svntest
.actions
.run_and_verify_svn(None, None, [], 'rm', B_path
)
1499 expected_output
= svntest
.wc
.State(wc_dir
, {
1500 'A/B' : Item(verb
='Deleting'),
1502 expected_status
.remove('A/B', 'A/B/lambda', 'A/B/E', 'A/B/E/beta', 'A/B/F')
1503 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
1504 expected_status
, None,
1505 None, None, None, None, wc_dir
)
1507 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
1508 expected_status
.tweak(wc_rev
=3)
1509 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
1511 # Replace the deleted directory with a new checkout of an old
1512 # version of the directory, this gives it a "plausible" URL that
1513 # could be part of the containing wc
1514 B_url
= sbox
.repo_url
+ '/A/B'
1515 svntest
.actions
.run_and_verify_svn(None, None, [],
1516 'checkout', '-r', '1', B_url
+ "@1",
1518 expected_status
= svntest
.wc
.State(B_path
, {
1526 expected_status
.tweak(wc_rev
=1, status
=' ')
1527 svntest
.actions
.run_and_verify_status(B_path
, expected_status
)
1529 # Make enclosing wc read only
1530 os
.chmod(os
.path
.join(wc_dir
, 'A', svntest
.main
.get_admin_name()), 0555)
1533 # Update of nested wc should still work
1534 expected_output
= svntest
.wc
.State(B_path
, {
1535 'E/alpha' : Item(status
='D '),
1537 expected_disk
= wc
.State('', {
1538 'lambda' : wc
.StateItem("This is the file 'lambda'.\n"),
1539 'E' : wc
.StateItem(),
1540 'E/beta' : wc
.StateItem("This is the file 'beta'.\n"),
1541 'F' : wc
.StateItem(),
1543 expected_status
.remove('E/alpha')
1544 expected_status
.tweak(wc_rev
=2)
1545 svntest
.actions
.run_and_verify_update(B_path
,
1549 None, None, None, None, None, 0,
1552 os
.chmod(os
.path
.join(wc_dir
, 'A', svntest
.main
.get_admin_name()), 0777)
1554 #----------------------------------------------------------------------
1556 def update_xml_unsafe_dir(sbox
):
1557 "update dir with xml-unsafe name"
1560 wc_dir
= sbox
.wc_dir
1562 # Make a backup copy of the working copy
1563 wc_backup
= sbox
.add_wc_path('backup')
1564 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
1566 # Make a couple of local mods to files
1567 test_path
= os
.path
.join(wc_dir
, ' foo & bar')
1568 svntest
.main
.run_svn(None, 'mkdir', test_path
)
1570 # Created expected output tree for 'svn ci'
1571 expected_output
= wc
.State(wc_dir
, {
1572 ' foo & bar' : Item(verb
='Adding'),
1575 # Create expected status tree; all local revisions should be at 1,
1576 # but 'foo & bar' should be at revision 2.
1577 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1578 expected_status
.add({
1579 ' foo & bar' : Item(status
=' ', wc_rev
=2),
1583 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
1584 expected_status
, None,
1585 None, None, None, None, wc_dir
)
1587 # chdir into the funky path, and update from there.
1590 expected_output
= wc
.State('', {
1592 expected_disk
= wc
.State('', {
1594 expected_status
= wc
.State('', {
1595 '' : Item(status
=' ', wc_rev
=2),
1597 svntest
.actions
.run_and_verify_update('', expected_output
, expected_disk
,
1600 #----------------------------------------------------------------------
1601 # eol-style handling during update with conflicts, scenario 1:
1602 # when update creates a conflict on a file, make sure the file and files
1603 # r<left>, r<right> and .mine are in the eol-style defined for that file.
1605 # This test for 'svn merge' can be found in merge_tests.py as
1606 # merge_conflict_markers_matching_eol.
1607 def conflict_markers_matching_eol(sbox
):
1608 "conflict markers should match the file's eol style"
1611 wc_dir
= sbox
.wc_dir
1614 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
1621 # Checkout a second working copy
1622 wc_backup
= sbox
.add_wc_path('backup')
1623 svntest
.actions
.run_and_verify_svn(None, None, [], 'checkout',
1624 sbox
.repo_url
, wc_backup
)
1626 # set starting revision
1629 expected_disk
= svntest
.main
.greek_state
.copy()
1630 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, cur_rev
)
1631 expected_backup_status
= svntest
.actions
.get_virginal_state(wc_backup
,
1634 path_backup
= os
.path
.join(wc_backup
, 'A', 'mu')
1636 # do the test for each eol-style
1637 for eol
, eolchar
in zip(['CRLF', 'CR', 'native', 'LF'],
1638 [crlf
, '\015', '\n', '\012']):
1639 # rewrite file mu and set the eol-style property.
1640 svntest
.main
.file_write(mu_path
, "This is the file 'mu'."+ eolchar
, 'wb')
1641 svntest
.main
.run_svn(None, 'propset', 'svn:eol-style', eol
, mu_path
)
1644 'A/mu' : Item("This is the file 'mu'." + eolchar
)
1646 expected_output
= svntest
.wc
.State(wc_dir
, {
1647 'A/mu' : Item(verb
='Sending'),
1649 expected_status
.tweak(wc_rev
= cur_rev
)
1650 expected_status
.add({
1651 'A/mu' : Item(status
=' ', wc_rev
= cur_rev
+ 1),
1654 # Commit the original change and note the 'base' revision number
1655 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
1656 expected_status
, None,
1657 None, None, None, None, wc_dir
)
1658 cur_rev
= cur_rev
+ 1
1661 svntest
.main
.run_svn(None, 'update', wc_backup
)
1663 # Make a local mod to mu
1664 svntest
.main
.file_append(mu_path
,
1665 'Original appended text for mu' + eolchar
)
1667 # Commit the original change and note the 'theirs' revision number
1668 svntest
.main
.run_svn(None, 'commit', '-m', 'test log', wc_dir
)
1669 cur_rev
= cur_rev
+ 1
1670 theirs_rev
= cur_rev
1672 # Make a local mod to mu, will conflict with the previous change
1673 svntest
.main
.file_append(path_backup
,
1674 'Conflicting appended text for mu' + eolchar
)
1676 # Create expected output tree for an update of the wc_backup.
1677 expected_backup_output
= svntest
.wc
.State(wc_backup
, {
1678 'A/mu' : Item(status
='C '),
1681 # Create expected disk tree for the update.
1682 expected_backup_disk
= expected_disk
.copy()
1684 # verify content of resulting conflicted file
1685 expected_backup_disk
.add({
1686 'A/mu' : Item(contents
= "This is the file 'mu'." + eolchar
+
1687 "<<<<<<< .mine" + eolchar
+
1688 "Conflicting appended text for mu" + eolchar
+
1689 "=======" + eolchar
+
1690 "Original appended text for mu" + eolchar
+
1691 ">>>>>>> .r" + str(cur_rev
) + eolchar
),
1693 # verify content of base(left) file
1694 expected_backup_disk
.add({
1695 'A/mu.r' + str(base_rev
) : Item(contents
= "This is the file 'mu'." +
1698 # verify content of theirs(right) file
1699 expected_backup_disk
.add({
1700 'A/mu.r' + str(theirs_rev
) : Item(contents
= "This is the file 'mu'." +
1702 "Original appended text for mu" + eolchar
)
1704 # verify content of mine file
1705 expected_backup_disk
.add({
1706 'A/mu.mine' : Item(contents
= "This is the file 'mu'." +
1708 "Conflicting appended text for mu" + eolchar
)
1711 # Create expected status tree for the update.
1712 expected_backup_status
.add({
1713 'A/mu' : Item(status
=' ', wc_rev
=cur_rev
),
1715 expected_backup_status
.tweak('A/mu', status
='C ')
1716 expected_backup_status
.tweak(wc_rev
= cur_rev
)
1718 # Do the update and check the results in three ways.
1719 svntest
.actions
.run_and_verify_update(wc_backup
,
1720 expected_backup_output
,
1721 expected_backup_disk
,
1722 expected_backup_status
,
1727 # cleanup for next run
1728 svntest
.main
.run_svn(None, 'revert', '-R', wc_backup
)
1729 svntest
.main
.run_svn(None, 'update', wc_dir
)
1731 # eol-style handling during update, scenario 2:
1732 # if part of that update is a propchange (add, change, delete) of
1733 # svn:eol-style, make sure the correct eol-style is applied before
1734 # calculating the merge (and conflicts if any)
1736 # This test for 'svn merge' can be found in merge_tests.py as
1737 # merge_eolstyle_handling.
1738 def update_eolstyle_handling(sbox
):
1739 "handle eol-style propchange during update"
1742 wc_dir
= sbox
.wc_dir
1744 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
1751 # Checkout a second working copy
1752 wc_backup
= sbox
.add_wc_path('backup')
1753 svntest
.actions
.run_and_verify_svn(None, None, [], 'checkout',
1754 sbox
.repo_url
, wc_backup
)
1755 path_backup
= os
.path
.join(wc_backup
, 'A', 'mu')
1757 # Test 1: add the eol-style property and commit, change mu in the second
1758 # working copy and update; there should be no conflict!
1759 svntest
.main
.run_svn(None, 'propset', 'svn:eol-style', "CRLF", mu_path
)
1760 svntest
.main
.run_svn(None,
1761 'commit', '-m', 'set eol-style property', wc_dir
)
1763 svntest
.main
.file_append_binary(path_backup
, 'Added new line of text.\012')
1765 expected_backup_disk
= svntest
.main
.greek_state
.copy()
1766 expected_backup_disk
.tweak(
1767 'A/mu', contents
= "This is the file 'mu'." + crlf
+
1768 "Added new line of text." + crlf
)
1769 expected_backup_output
= svntest
.wc
.State(wc_backup
, {
1770 'A/mu' : Item(status
='GU'),
1772 expected_backup_status
= svntest
.actions
.get_virginal_state(wc_backup
, 2)
1773 expected_backup_status
.tweak('A/mu', status
='M ')
1775 svntest
.actions
.run_and_verify_update(wc_backup
,
1776 expected_backup_output
,
1777 expected_backup_disk
,
1778 expected_backup_status
,
1781 # Test 2: now change the eol-style property to another value and commit,
1782 # update the still changed mu in the second working copy; there should be
1784 svntest
.main
.run_svn(None, 'propset', 'svn:eol-style', "CR", mu_path
)
1785 svntest
.main
.run_svn(None,
1786 'commit', '-m', 'set eol-style property', wc_dir
)
1788 expected_backup_disk
= svntest
.main
.greek_state
.copy()
1789 expected_backup_disk
.add({
1790 'A/mu' : Item(contents
= "This is the file 'mu'.\015" +
1791 "Added new line of text.\015")
1793 expected_backup_output
= svntest
.wc
.State(wc_backup
, {
1794 'A/mu' : Item(status
='GU'),
1796 expected_backup_status
= svntest
.actions
.get_virginal_state(wc_backup
, 3)
1797 expected_backup_status
.tweak('A/mu', status
='M ')
1798 svntest
.actions
.run_and_verify_update(wc_backup
,
1799 expected_backup_output
,
1800 expected_backup_disk
,
1801 expected_backup_status
,
1804 # Test 3: now delete the eol-style property and commit, update the still
1805 # changed mu in the second working copy; there should be no conflict!
1806 # EOL of mu should be unchanged (=CR).
1807 svntest
.main
.run_svn(None, 'propdel', 'svn:eol-style', mu_path
)
1808 svntest
.main
.run_svn(None,
1809 'commit', '-m', 'del eol-style property', wc_dir
)
1811 expected_backup_disk
= svntest
.main
.greek_state
.copy()
1812 expected_backup_disk
.add({
1813 'A/mu' : Item(contents
= "This is the file 'mu'.\015" +
1814 "Added new line of text.\015")
1816 expected_backup_output
= svntest
.wc
.State(wc_backup
, {
1817 'A/mu' : Item(status
=' U'),
1819 expected_backup_status
= svntest
.actions
.get_virginal_state(wc_backup
, 4)
1820 expected_backup_status
.tweak('A/mu', status
='M ')
1821 svntest
.actions
.run_and_verify_update(wc_backup
,
1822 expected_backup_output
,
1823 expected_backup_disk
,
1824 expected_backup_status
,
1827 # Bug in which "update" put a bogus revision number on a schedule-add file,
1828 # causing the wrong version of it to be committed.
1829 def update_copy_of_old_rev(sbox
):
1830 "update schedule-add copy of old rev"
1833 wc_dir
= sbox
.wc_dir
1835 dir = os
.path
.join(wc_dir
, 'A')
1836 dir2
= os
.path
.join(wc_dir
, 'A2')
1837 file = os
.path
.join(dir, 'mu')
1838 file2
= os
.path
.join(dir2
, 'mu')
1839 url
= sbox
.repo_url
+ '/A/mu'
1840 url2
= sbox
.repo_url
+ '/A2/mu'
1842 # Remember the original text of the file
1843 text_r1
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
1846 # Commit a different version of the file
1847 svntest
.main
.file_write(file, "Second revision of 'mu'\n")
1848 svntest
.actions
.run_and_verify_svn(None, None, [],
1849 'ci', '-m', '', wc_dir
)
1851 # Copy an old revision of its directory into a new path in the WC
1852 svntest
.actions
.run_and_verify_svn(None, None, [],
1853 'cp', '-r1', dir, dir2
)
1855 # Update. (Should do nothing, but added a bogus "revision" in "entries".)
1856 svntest
.actions
.run_and_verify_svn(None, None, [],
1859 # Commit, and check that it says it's committing the right thing
1860 exp_out
= ['Adding ' + dir2
+ '\n',
1862 'Committed revision 3.\n']
1863 svntest
.actions
.run_and_verify_svn(None, exp_out
, [],
1864 'ci', '-m', '', wc_dir
)
1866 # Verify the committed file's content
1867 svntest
.actions
.run_and_verify_svn(None, text_r1
, [],
1870 #----------------------------------------------------------------------
1871 def forced_update(sbox
):
1872 "forced update tolerates obstructions to adds"
1875 wc_dir
= sbox
.wc_dir
1877 # Make a backup copy of the working copy
1878 wc_backup
= sbox
.add_wc_path('backup')
1879 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
1881 # Make a couple of local mods to files
1882 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
1883 rho_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'rho')
1884 svntest
.main
.file_append(mu_path
, 'appended mu text')
1885 svntest
.main
.file_append(rho_path
, 'new appended text for rho')
1888 nu_path
= os
.path
.join(wc_dir
, 'A', 'B', 'F', 'nu')
1889 svntest
.main
.file_append(nu_path
, "This is the file 'nu'\n")
1890 svntest
.main
.run_svn(None, 'add', nu_path
)
1891 kappa_path
= os
.path
.join(wc_dir
, 'kappa')
1892 svntest
.main
.file_append(kappa_path
, "This is the file 'kappa'\n")
1893 svntest
.main
.run_svn(None, 'add', kappa_path
)
1895 # Add a dir with two files
1896 I_path
= os
.path
.join(wc_dir
, 'A', 'C', 'I')
1898 svntest
.main
.run_svn(None, 'add', I_path
)
1899 upsilon_path
= os
.path
.join(I_path
, 'upsilon')
1900 svntest
.main
.file_append(upsilon_path
, "This is the file 'upsilon'\n")
1901 svntest
.main
.run_svn(None, 'add', upsilon_path
)
1902 zeta_path
= os
.path
.join(I_path
, 'zeta')
1903 svntest
.main
.file_append(zeta_path
, "This is the file 'zeta'\n")
1904 svntest
.main
.run_svn(None, 'add', zeta_path
)
1906 # Created expected output tree for 'svn ci'
1907 expected_output
= wc
.State(wc_dir
, {
1908 'A/mu' : Item(verb
='Sending'),
1909 'A/D/G/rho' : Item(verb
='Sending'),
1910 'A/B/F/nu' : Item(verb
='Adding'),
1911 'kappa' : Item(verb
='Adding'),
1912 'A/C/I' : Item(verb
='Adding'),
1913 'A/C/I/upsilon' : Item(verb
='Adding'),
1914 'A/C/I/zeta' : Item(verb
='Adding'),
1917 # Create expected status tree.
1918 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1919 expected_status
.add({
1920 'A/B/F/nu' : Item(status
=' ', wc_rev
=2),
1921 'kappa' : Item(status
=' ', wc_rev
=2),
1922 'A/C/I' : Item(status
=' ', wc_rev
=2),
1923 'A/C/I/upsilon' : Item(status
=' ', wc_rev
=2),
1924 'A/C/I/zeta' : Item(status
=' ', wc_rev
=2),
1926 expected_status
.tweak('A/mu', 'A/D/G/rho', wc_rev
=2)
1929 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
1930 expected_status
, None,
1931 None, None, None, None, wc_dir
)
1933 # Make a local mod to mu that will merge cleanly.
1934 backup_mu_path
= os
.path
.join(wc_backup
, 'A', 'mu')
1935 svntest
.main
.file_append(backup_mu_path
, 'appended mu text')
1937 # Create unversioned files and dir that will obstruct A/B/F/nu, kappa,
1938 # A/C/I, and A/C/I/upsilon coming from repos during update.
1939 # The obstructing nu has the same contents as the repos, while kappa and
1940 # upsilon differ, which means the latter two should show as modified after
1941 # the forced update.
1942 nu_path
= os
.path
.join(wc_backup
, 'A', 'B', 'F', 'nu')
1943 svntest
.main
.file_append(nu_path
, "This is the file 'nu'\n")
1944 kappa_path
= os
.path
.join(wc_backup
, 'kappa')
1945 svntest
.main
.file_append(kappa_path
,
1946 "This is the OBSTRUCTING file 'kappa'\n")
1947 I_path
= os
.path
.join(wc_backup
, 'A', 'C', 'I')
1949 upsilon_path
= os
.path
.join(I_path
, 'upsilon')
1950 svntest
.main
.file_append(upsilon_path
,
1951 "This is the OBSTRUCTING file 'upsilon'\n")
1953 # Create expected output tree for an update of the wc_backup.
1954 # mu and rho are run of the mill update operations; merge and update
1956 # kappa, nu, I, and upsilon all 'E'xisted as unversioned items in the WC.
1957 # While the dir I does exist, zeta does not so it's just an add.
1958 expected_output
= wc
.State(wc_backup
, {
1959 'A/mu' : Item(status
='G '),
1960 'A/D/G/rho' : Item(status
='U '),
1961 'kappa' : Item(status
='E '),
1962 'A/B/F/nu' : Item(status
='E '),
1963 'A/C/I' : Item(status
='E '),
1964 'A/C/I/upsilon' : Item(status
='E '),
1965 'A/C/I/zeta' : Item(status
='A '),
1968 # Create expected output tree for an update of the wc_backup.
1970 # - mu and rho are run of the mill update operations; merge and update
1973 # - kappa, nu, I, and upsilon all 'E'xisted as unversioned items in the WC.
1975 # - While the dir I does exist, I/zeta does not so it's just an add.
1976 expected_disk
= svntest
.main
.greek_state
.copy()
1978 'A/B/F/nu' : Item("This is the file 'nu'\n"),
1979 'kappa' : Item("This is the OBSTRUCTING file 'kappa'\n"),
1981 'A/C/I/upsilon' : Item("This is the OBSTRUCTING file 'upsilon'\n"),
1982 'A/C/I/zeta' : Item("This is the file 'zeta'\n"),
1984 expected_disk
.tweak('A/mu',
1985 contents
=expected_disk
.desc
['A/mu'].contents
1986 + 'appended mu text')
1987 expected_disk
.tweak('A/D/G/rho',
1988 contents
=expected_disk
.desc
['A/D/G/rho'].contents
1989 + 'new appended text for rho')
1991 # Create expected status tree for the update. Since the obstructing
1992 # kappa and upsilon differ from the repos, they should show as modified.
1993 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 2)
1994 expected_status
.add({
1995 'A/B/F/nu' : Item(status
=' ', wc_rev
=2),
1996 'A/C/I' : Item(status
=' ', wc_rev
=2),
1997 'A/C/I/zeta' : Item(status
=' ', wc_rev
=2),
1998 'kappa' : Item(status
='M ', wc_rev
=2),
1999 'A/C/I/upsilon' : Item(status
='M ', wc_rev
=2),
2002 # Perform forced update and check the results in three ways.
2003 svntest
.actions
.run_and_verify_update(wc_backup
,
2007 None, None, None, None, None, 0,
2008 wc_backup
, '--force')
2010 #----------------------------------------------------------------------
2011 def forced_update_failures(sbox
):
2012 "forced up fails with some types of obstructions"
2015 wc_dir
= sbox
.wc_dir
2017 # Make a backup copy of the working copy
2018 wc_backup
= sbox
.add_wc_path('backup')
2019 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
2022 nu_path
= os
.path
.join(wc_dir
, 'A', 'B', 'F', 'nu')
2023 svntest
.main
.file_append(nu_path
, "This is the file 'nu'\n")
2024 svntest
.main
.run_svn(None, 'add', nu_path
)
2027 I_path
= os
.path
.join(wc_dir
, 'A', 'C', 'I')
2029 svntest
.main
.run_svn(None, 'add', I_path
)
2031 # Created expected output tree for 'svn ci'
2032 expected_output
= wc
.State(wc_dir
, {
2033 'A/B/F/nu' : Item(verb
='Adding'),
2034 'A/C/I' : Item(verb
='Adding'),
2037 # Create expected status tree.
2038 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2039 expected_status
.add({
2040 'A/B/F/nu' : Item(status
=' ', wc_rev
=2),
2041 'A/C/I' : Item(status
=' ', wc_rev
=2),
2045 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
2046 expected_status
, None,
2047 None, None, None, None, wc_dir
)
2049 # Create an unversioned dir A/B/F/nu that will obstruct the file of the
2050 # same name coming from the repository. Create an unversioned file A/C/I
2051 # that will obstruct the dir of the same name.
2052 nu_path
= os
.path
.join(wc_backup
, 'A', 'B', 'F', 'nu')
2054 I_path
= os
.path
.join(wc_backup
, 'A', 'C', 'I')
2055 svntest
.main
.file_append(I_path
,
2056 "This is the file 'I'...shouldn't I be a dir?\n")
2058 # A forced update that tries to add a file when an unversioned directory
2059 # of the same name already exists should fail.
2060 F_Path
= os
.path
.join(wc_backup
, 'A', 'B', 'F')
2061 svntest
.actions
.run_and_verify_update(F_Path
, None, None, None,
2062 ".*Failed to add file.*" + \
2063 "a non-file object of the " + \
2064 "same name already exists",
2065 None, None, None, None, 0, F_Path
,
2068 # A forced update that tries to add a directory when an unversioned file
2069 # of the same name already exists should fail.
2070 C_Path
= os
.path
.join(wc_backup
, 'A', 'C')
2071 svntest
.actions
.run_and_verify_update(C_Path
, None, None, None,
2072 ".*Failed to add directory.*" + \
2073 "a non-directory object of the " + \
2074 "same name already exists",
2075 None, None, None, None, 0, C_Path
,
2078 # A forced update that tries to add a directory when a versioned directory
2079 # of the same name already exists should fail.
2081 # Remove the file A/C/I and make it a versioned directory.
2082 I_url
= sbox
.repo_url
+ "/A/C/I"
2085 so
, se
= svntest
.actions
.run_and_verify_svn("Unexpected error during co",
2086 ['Checked out revision 2.\n'],
2087 [], "co", I_url
, I_path
)
2089 svntest
.actions
.run_and_verify_update(C_Path
, None, None, None,
2090 ".*Failed to add " + \
2091 "directory.*a versioned directory " + \
2092 "of the same name already exists",
2093 None, None, None, None, 0, C_Path
,
2096 #----------------------------------------------------------------------
2097 # Test for issue #2556. The tests maps a virtual drive to a working copy
2098 # and tries some basic update, commit and status actions on the virtual
2100 def update_wc_on_windows_drive(sbox
):
2101 "update wc on the root of a Windows (virtual) drive"
2103 def find_the_next_available_drive_letter():
2104 "find the first available drive"
2106 # get the list of used drive letters, use some Windows specific function.
2110 drives
=win32api
.GetLogicalDriveStrings()
2111 drives
=drives
.split('\000')
2113 for d
in range(ord('G'), ord('Z')+1):
2115 if not drive
+ ':\\' in drives
:
2122 # just create an empty folder, we'll checkout later.
2123 sbox
.build(create_wc
= False)
2124 svntest
.main
.safe_rmtree(sbox
.wc_dir
)
2125 os
.mkdir(sbox
.wc_dir
)
2127 # create a virtual drive to the working copy folder
2128 drive
= find_the_next_available_drive_letter()
2132 os
.popen3('subst ' + drive
+': ' + sbox
.wc_dir
, 't')
2133 wc_dir
= drive
+ ':/'
2134 was_cwd
= os
.getcwd()
2137 svntest
.actions
.run_and_verify_svn(None, None, [],
2139 sbox
.repo_url
, wc_dir
)
2141 # Make some local modifications
2142 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
2143 svntest
.main
.file_append(mu_path
, '\nAppended text for mu')
2144 zeta_path
= os
.path
.join(wc_dir
, 'zeta')
2145 svntest
.main
.file_append(zeta_path
, "This is the file 'zeta'\n")
2146 svntest
.main
.run_svn(None, 'add', zeta_path
)
2149 expected_output
= svntest
.wc
.State(wc_dir
, {
2150 'A/mu' : Item(verb
='Sending'),
2151 'zeta' : Item(verb
='Adding'),
2153 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2154 expected_status
.tweak('A/mu', wc_rev
=2)
2155 expected_status
.add({
2156 'zeta' : Item(status
=' ', wc_rev
=2),
2158 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
2159 expected_status
, None,
2160 None, None, None, None,
2163 # Non recursive commit
2164 dir1_path
= os
.path
.join(wc_dir
, 'dir1')
2166 svntest
.main
.run_svn(None, 'add', '-N', dir1_path
)
2167 file1_path
= os
.path
.join(dir1_path
, 'file1')
2168 svntest
.main
.file_append(file1_path
, "This is the file 'file1'\n")
2169 svntest
.main
.run_svn(None, 'add', '-N', file1_path
)
2171 expected_output
= svntest
.wc
.State(wc_dir
, {
2172 'dir1' : Item(verb
='Adding'),
2173 'dir1/file1' : Item(verb
='Adding'),
2175 expected_status
.add({
2176 'dir1' : Item(status
=' ', wc_rev
=3),
2177 'dir1/file1' : Item(status
=' ', wc_rev
=3),
2179 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
2180 expected_status
, None,
2181 None, None, None, None,
2184 dir1_path
, file1_path
)
2186 # revert to previous revision to test update
2189 expected_disk
= svntest
.main
.greek_state
.copy()
2190 expected_output
= svntest
.wc
.State(wc_dir
, {
2191 'A/mu' : Item(status
='U '),
2192 'zeta' : Item(status
='D '),
2193 'dir1' : Item(status
='D '),
2195 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2196 svntest
.actions
.run_and_verify_update(wc_dir
,
2200 None, None, None, None, None, 0,
2205 # update to the latest version, but use the relative path 'X:'
2206 wc_dir
= drive
+ ":"
2207 expected_output
= svntest
.wc
.State(wc_dir
, {
2208 'A/mu' : Item(status
='U '),
2209 'zeta' : Item(status
='A '),
2210 'dir1' : Item(status
='A '),
2211 'dir1/file1' : Item(status
='A '),
2213 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 3)
2214 expected_status
.add({
2215 'dir1' : Item(status
=' ', wc_rev
=3),
2216 'dir1/file1' : Item(status
=' ', wc_rev
=3),
2217 'zeta' : Item(status
=' ', wc_rev
=3),
2220 'zeta' : Item("This is the file 'zeta'\n"),
2221 'dir1/file1': Item("This is the file 'file1'\n"),
2223 expected_disk
.tweak('A/mu', contents
= expected_disk
.desc
['A/mu'].contents
2224 + '\nAppended text for mu')
2225 svntest
.actions
.run_and_verify_update(wc_dir
,
2232 # cleanup the virtual drive
2233 os
.popen3('subst /D ' + drive
+': ', 't')
2235 # Issue #2618: update a working copy with a replaced file.
2236 def update_wc_with_replaced_file(sbox
):
2237 "update wc containing a replaced-with-history file"
2240 wc_dir
= sbox
.wc_dir
2242 # Make a backup copy of the working copy.
2243 wc_backup
= sbox
.add_wc_path('backup')
2244 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
2246 # we need a change in the repository
2247 iota_path
= os
.path
.join(wc_dir
, 'iota')
2248 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
2249 iota_bu_path
= os
.path
.join(wc_backup
, 'iota')
2250 svntest
.main
.file_append(iota_bu_path
, "New line in 'iota'\n")
2251 svntest
.main
.run_svn(None,
2252 'ci', wc_backup
, '-m', 'changed file')
2254 # First, a replacement without history.
2255 svntest
.main
.run_svn(None, 'rm', iota_path
)
2256 svntest
.main
.file_append(iota_path
, "")
2257 svntest
.main
.run_svn(None, 'add', iota_path
)
2259 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2260 expected_status
.tweak('iota', status
='R ', wc_rev
='1')
2261 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
2264 expected_output
= svntest
.wc
.State(wc_dir
, {
2265 'iota' : Item(status
='C '),
2267 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
2268 expected_status
.add({
2269 'iota' : Item(status
='C ', wc_rev
='2'),
2271 expected_disk
= svntest
.main
.greek_state
.copy()
2272 expected_disk
.tweak('iota',
2273 contents
="\n".join(["<<<<<<< .mine",
2275 "This is the file 'iota'.",
2276 "New line in 'iota'",
2279 conflict_files
= [ 'iota.*\.r1', 'iota.*\.r2', 'iota.*\.mine' ]
2280 svntest
.actions
.run_and_verify_update(wc_dir
,
2285 svntest
.tree
.detect_conflict_files
,
2288 # Make us a working copy with a 'replace-with-history' file.
2289 svntest
.main
.run_svn(None, 'revert', iota_path
)
2290 expected_output
= svntest
.wc
.State(wc_dir
, {
2291 'iota' : Item(status
='U '),
2293 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2294 expected_disk
= svntest
.main
.greek_state
.copy()
2295 svntest
.actions
.run_and_verify_update(wc_dir
,
2300 None, None, None, None, 0,
2303 svntest
.main
.run_svn(None, 'rm', iota_path
)
2304 svntest
.main
.run_svn(None, 'cp', mu_path
, iota_path
)
2306 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2307 expected_status
.tweak('iota', status
='R ', copied
='+', wc_rev
='-')
2308 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
2311 expected_output
= svntest
.wc
.State(wc_dir
, {
2312 'iota' : Item(status
='C '),
2314 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
2315 expected_status
.add({
2316 'iota' : Item(status
='CM', wc_rev
='-', copied
='+'),
2318 expected_disk
= svntest
.main
.greek_state
.copy()
2319 expected_disk
.tweak('iota',
2320 contents
="\n".join(["<<<<<<< .mine",
2321 "This is the file 'mu'.",
2323 "This is the file 'iota'.",
2324 "New line in 'iota'",
2327 conflict_files
= [ 'iota.*\.r1', 'iota.*\.r2', 'iota.*\.mine' ]
2328 svntest
.actions
.run_and_verify_update(wc_dir
,
2333 svntest
.tree
.detect_conflict_files
,
2336 #----------------------------------------------------------------------
2337 def update_with_obstructing_additions(sbox
):
2338 "update handles obstructing paths scheduled for add"
2341 wc_dir
= sbox
.wc_dir
2343 # Make a backup copy of the working copy
2344 wc_backup
= sbox
.add_wc_path('backup')
2345 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
2347 # Add files and dirs to the repos via the first WC. Each of these
2348 # will be added to the backup WC via an update:
2350 # A/B/upsilon: Identical to the file scheduled for addition in
2353 # A/C/nu: A "normal" add, won't exist in the backup WC.
2355 # A/D/kappa: Textual and property conflict with the file scheduled
2356 # for addition in the backup WC.
2358 # A/D/epsilon: Textual conflict with the file scheduled for addition.
2360 # A/D/zeta: Prop conflict with the file scheduled for addition.
2362 # Three new dirs that will also be scheduled for addition:
2363 # A/D/H/I: No props on either WC or REPOS.
2364 # A/D/H/I/J: Prop conflict with the scheduled add.
2365 # A/D/H/I/K: Same (mergeable) prop on WC and REPOS.
2367 # A/D/H/I/K/xi: Identical to the file scheduled for addition in
2368 # the backup WC. No props.
2370 # A/D/H/I/L: A "normal" dir add, won't exist in the backup WC.
2372 # A/D/H/I/J/eta: Conflicts with the file scheduled for addition in
2373 # the backup WC. No props.
2374 upsilon_path
= os
.path
.join(wc_dir
, 'A', 'B', 'upsilon')
2375 svntest
.main
.file_append(upsilon_path
, "This is the file 'upsilon'\n")
2376 nu_path
= os
.path
.join(wc_dir
, 'A', 'C', 'nu')
2377 svntest
.main
.file_append(nu_path
, "This is the file 'nu'\n")
2378 kappa_path
= os
.path
.join(wc_dir
, 'A', 'D', 'kappa')
2379 svntest
.main
.file_append(kappa_path
, "This is REPOS file 'kappa'\n")
2380 epsilon_path
= os
.path
.join(wc_dir
, 'A', 'D', 'epsilon')
2381 svntest
.main
.file_append(epsilon_path
, "This is REPOS file 'epsilon'\n")
2382 zeta_path
= os
.path
.join(wc_dir
, 'A', 'D', 'zeta')
2383 svntest
.main
.file_append(zeta_path
, "This is the file 'zeta'\n")
2384 I_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'I')
2386 J_path
= os
.path
.join(I_path
, 'J')
2388 K_path
= os
.path
.join(I_path
, 'K')
2390 L_path
= os
.path
.join(I_path
, 'L')
2392 xi_path
= os
.path
.join(K_path
, 'xi')
2393 svntest
.main
.file_append(xi_path
, "This is the file 'xi'\n")
2394 eta_path
= os
.path
.join(J_path
, 'eta')
2395 svntest
.main
.file_append(eta_path
, "This is REPOS file 'eta'\n")
2396 svntest
.main
.run_svn(None, 'add', upsilon_path
, nu_path
,
2397 kappa_path
, epsilon_path
, zeta_path
, I_path
)
2399 # Set props that will conflict with scheduled adds.
2400 svntest
.main
.run_svn(None, 'propset', 'propname1', 'propval-REPOS',
2402 svntest
.main
.run_svn(None, 'propset', 'propname1', 'propval-REPOS',
2404 svntest
.main
.run_svn(None, 'propset', 'propname1', 'propval-REPOS',
2407 # Set prop that will match with scheduled add.
2408 svntest
.main
.run_svn(None, 'propset', 'propname1', 'propval-SAME',
2410 svntest
.main
.run_svn(None, 'propset', 'propname1', 'propval-SAME',
2413 # Created expected output tree for 'svn ci'
2414 expected_output
= wc
.State(wc_dir
, {
2415 'A/B/upsilon' : Item(verb
='Adding'),
2416 'A/C/nu' : Item(verb
='Adding'),
2417 'A/D/kappa' : Item(verb
='Adding'),
2418 'A/D/epsilon' : Item(verb
='Adding'),
2419 'A/D/zeta' : Item(verb
='Adding'),
2420 'A/D/H/I' : Item(verb
='Adding'),
2421 'A/D/H/I/J' : Item(verb
='Adding'),
2422 'A/D/H/I/J/eta' : Item(verb
='Adding'),
2423 'A/D/H/I/K' : Item(verb
='Adding'),
2424 'A/D/H/I/K/xi' : Item(verb
='Adding'),
2425 'A/D/H/I/L' : Item(verb
='Adding'),
2428 # Create expected status tree.
2429 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2430 expected_status
.add({
2431 'A/B/upsilon' : Item(status
=' ', wc_rev
=2),
2432 'A/C/nu' : Item(status
=' ', wc_rev
=2),
2433 'A/D/kappa' : Item(status
=' ', wc_rev
=2),
2434 'A/D/epsilon' : Item(status
=' ', wc_rev
=2),
2435 'A/D/zeta' : Item(status
=' ', wc_rev
=2),
2436 'A/D/H/I' : Item(status
=' ', wc_rev
=2),
2437 'A/D/H/I/J' : Item(status
=' ', wc_rev
=2),
2438 'A/D/H/I/J/eta' : Item(status
=' ', wc_rev
=2),
2439 'A/D/H/I/K' : Item(status
=' ', wc_rev
=2),
2440 'A/D/H/I/K/xi' : Item(status
=' ', wc_rev
=2),
2441 'A/D/H/I/L' : Item(status
=' ', wc_rev
=2),
2445 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
2446 expected_status
, None,
2447 None, None, None, None, wc_dir
)
2449 # Create various paths scheduled for addition which will obstruct
2450 # the adds coming from the repos.
2451 upsilon_backup_path
= os
.path
.join(wc_backup
, 'A', 'B', 'upsilon')
2452 svntest
.main
.file_append(upsilon_backup_path
,
2453 "This is the file 'upsilon'\n")
2454 kappa_backup_path
= os
.path
.join(wc_backup
, 'A', 'D', 'kappa')
2455 svntest
.main
.file_append(kappa_backup_path
,
2456 "This is WC file 'kappa'\n")
2457 epsilon_backup_path
= os
.path
.join(wc_backup
, 'A', 'D', 'epsilon')
2458 svntest
.main
.file_append(epsilon_backup_path
,
2459 "This is WC file 'epsilon'\n")
2460 zeta_backup_path
= os
.path
.join(wc_backup
, 'A', 'D', 'zeta')
2461 svntest
.main
.file_append(zeta_backup_path
, "This is the file 'zeta'\n")
2462 I_backup_path
= os
.path
.join(wc_backup
, 'A', 'D', 'H', 'I')
2463 os
.mkdir(I_backup_path
)
2464 J_backup_path
= os
.path
.join(I_backup_path
, 'J')
2465 os
.mkdir(J_backup_path
)
2466 K_backup_path
= os
.path
.join(I_backup_path
, 'K')
2467 os
.mkdir(K_backup_path
)
2468 xi_backup_path
= os
.path
.join(K_backup_path
, 'xi')
2469 svntest
.main
.file_append(xi_backup_path
, "This is the file 'xi'\n")
2470 eta_backup_path
= os
.path
.join(J_backup_path
, 'eta')
2471 svntest
.main
.file_append(eta_backup_path
, "This is WC file 'eta'\n")
2473 svntest
.main
.run_svn(None, 'add', upsilon_backup_path
, kappa_backup_path
,
2474 epsilon_backup_path
, zeta_backup_path
, I_backup_path
)
2476 # Set prop that will conflict with add from repos.
2477 svntest
.main
.run_svn(None, 'propset', 'propname1', 'propval-WC',
2479 svntest
.main
.run_svn(None, 'propset', 'propname1', 'propval-WC',
2481 svntest
.main
.run_svn(None, 'propset', 'propname1', 'propval-WC',
2484 # Set prop that will match add from repos.
2485 svntest
.main
.run_svn(None, 'propset', 'propname1', 'propval-SAME',
2486 epsilon_backup_path
)
2487 svntest
.main
.run_svn(None, 'propset', 'propname1', 'propval-SAME',
2490 # Create expected output tree for an update of the wc_backup.
2491 expected_output
= wc
.State(wc_backup
, {
2492 'A/B/upsilon' : Item(status
='E '),
2493 'A/C/nu' : Item(status
='A '),
2494 'A/D/H/I' : Item(status
='E '),
2495 'A/D/H/I/J' : Item(status
='EC'),
2496 'A/D/H/I/J/eta' : Item(status
='C '),
2497 'A/D/H/I/K' : Item(status
='EG'),
2498 'A/D/H/I/K/xi' : Item(status
='E '),
2499 'A/D/H/I/L' : Item(status
='A '),
2500 'A/D/kappa' : Item(status
='CC'),
2501 'A/D/epsilon' : Item(status
='CG'),
2502 'A/D/zeta' : Item(status
='EC'),
2505 # Create expected disk for update of wc_backup.
2506 expected_disk
= svntest
.main
.greek_state
.copy()
2508 'A/B/upsilon' : Item("This is the file 'upsilon'\n"),
2509 'A/C/nu' : Item("This is the file 'nu'\n"),
2511 'A/D/H/I/J' : Item(props
={'propname1' : 'propval-WC'}),
2512 'A/D/H/I/J/eta' : Item("\n".join(["<<<<<<< .mine",
2513 "This is WC file 'eta'",
2515 "This is REPOS file 'eta'",
2518 'A/D/H/I/K' : Item(props
={'propname1' : 'propval-SAME'}),
2519 'A/D/H/I/K/xi' : Item("This is the file 'xi'\n"),
2520 'A/D/H/I/L' : Item(),
2521 'A/D/kappa' : Item("\n".join(["<<<<<<< .mine",
2522 "This is WC file 'kappa'",
2524 "This is REPOS file 'kappa'",
2527 props
={'propname1' : 'propval-WC'}),
2528 'A/D/epsilon' : Item("\n".join(["<<<<<<< .mine",
2529 "This is WC file 'epsilon'",
2531 "This is REPOS file 'epsilon'",
2534 props
={'propname1' : 'propval-SAME'}),
2535 'A/D/zeta' : Item("This is the file 'zeta'\n",
2536 props
={'propname1' : 'propval-WC'}),
2539 # Create expected status tree for the update. Since the obstructing
2540 # kappa and upsilon differ from the repos, they should show as modified.
2541 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 2)
2542 expected_status
.add({
2543 'A/B/upsilon' : Item(status
=' ', wc_rev
=2),
2544 'A/C/nu' : Item(status
=' ', wc_rev
=2),
2545 'A/D/H/I' : Item(status
=' ', wc_rev
=2),
2546 'A/D/H/I/J' : Item(status
=' C', wc_rev
=2),
2547 'A/D/H/I/J/eta' : Item(status
='C ', wc_rev
=2),
2548 'A/D/H/I/K' : Item(status
=' ', wc_rev
=2),
2549 'A/D/H/I/K/xi' : Item(status
=' ', wc_rev
=2),
2550 'A/D/H/I/L' : Item(status
=' ', wc_rev
=2),
2551 'A/D/kappa' : Item(status
='CC', wc_rev
=2),
2552 'A/D/epsilon' : Item(status
='C ', wc_rev
=2),
2553 'A/D/zeta' : Item(status
=' C', wc_rev
=2),
2556 # "Extra" files that we expect to result from the conflicts.
2557 extra_files
= ['eta\.r0', 'eta\.r2', 'eta\.mine',
2558 'kappa\.r0', 'kappa\.r2', 'kappa\.mine',
2559 'epsilon\.r0', 'epsilon\.r2', 'epsilon\.mine',
2560 'kappa.prej', 'zeta.prej', 'dir_conflicts.prej']
2562 # Perform forced update and check the results in three
2563 # ways (including props).
2564 svntest
.actions
.run_and_verify_update(wc_backup
,
2569 svntest
.tree
.detect_conflict_files
,
2570 extra_files
, None, None, 1,
2573 # Some obstructions are still not permitted:
2575 # Test that file and dir obstructions scheduled for addition *with*
2576 # history fail when update tries to add the same path.
2578 # URL to URL copy of A/D/G to A/M.
2579 G_URL
= sbox
.repo_url
+ '/A/D/G'
2580 M_URL
= sbox
.repo_url
+ '/A/M'
2581 svntest
.actions
.run_and_verify_svn("Copy error:", None, [],
2582 'cp', G_URL
, M_URL
, '-m', '')
2584 # WC to WC copy of A/D/H to A/M, M now scheduled for addition with
2585 # history in WC and pending addition from the repos.
2586 H_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H')
2587 A_path
= os
.path
.join(wc_dir
, 'A')
2588 M_path
= os
.path
.join(wc_dir
, 'A', 'M')
2590 svntest
.actions
.run_and_verify_svn("Copy error:", None, [],
2591 'cp', H_path
, M_path
)
2593 # URL to URL copy of A/D/H/omega to omicron.
2594 omega_URL
= sbox
.repo_url
+ '/A/D/H/omega'
2595 omicron_URL
= sbox
.repo_url
+ '/omicron'
2596 svntest
.actions
.run_and_verify_svn("Copy error:", None, [],
2597 'cp', omega_URL
, omicron_URL
,
2600 # WC to WC copy of A/D/H/chi to omicron, omicron now scheduled for
2601 # addition with history in WC and pending addition from the repos.
2602 chi_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'chi')
2603 omicron_path
= os
.path
.join(wc_dir
, 'omicron')
2605 svntest
.actions
.run_and_verify_svn("Copy error:", None, [],
2609 # Try to update M's Parent.
2610 svntest
.actions
.run_and_verify_update(A_path
, expected_output
,
2611 expected_disk
, expected_status
,
2612 "svn: Failed to add " \
2613 "directory '.*M': a versioned " \
2614 "directory of the same name " \
2616 None, None, None, None, 0)
2618 # --force shouldn't help either.
2619 svntest
.actions
.run_and_verify_update(wc_dir
, expected_output
,
2620 expected_disk
, expected_status
,
2621 "svn: Failed to add " \
2622 "directory '.*M': a versioned " \
2623 "directory of the same name " \
2625 None, None, None, None, 0,
2628 # Try to update omicron's parent, non-recusively so as not to
2629 # try and update M first.
2630 svntest
.actions
.run_and_verify_update(wc_dir
, expected_output
,
2631 expected_disk
, expected_status
,
2632 "Failed to add file '.*omicron': " \
2633 "a file of the same name is " \
2634 "already scheduled for addition " \
2636 None, None, None, None, 0,
2639 # Again, --force shouldn't matter.
2640 svntest
.actions
.run_and_verify_update(wc_dir
, expected_output
,
2641 expected_disk
, expected_status
,
2642 "Failed to add file '.*omicron': " \
2643 "a file of the same name is " \
2644 "already scheduled for addition " \
2646 None, None, None, None, 0,
2647 wc_dir
, '-N', '--force')
2649 # Test for issue #2022: Update shouldn't touch conflicted files.
2650 def update_conflicted(sbox
):
2651 "update conflicted files"
2653 wc_dir
= sbox
.wc_dir
2654 iota_path
= os
.path
.join(wc_dir
, 'iota')
2655 lambda_path
= os
.path
.join(wc_dir
, 'A', 'B', 'lambda')
2656 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
2657 D_path
= os
.path
.join(wc_dir
, 'A', 'D')
2658 pi_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'pi')
2660 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2662 # Make some modifications to the files and a dir, creating r2.
2663 svntest
.main
.file_append(iota_path
, 'Original appended text for iota\n')
2664 svntest
.main
.run_svn(None, 'propset', 'prop', 'val', lambda_path
)
2665 svntest
.main
.file_append(mu_path
, 'Original appended text for mu\n')
2666 svntest
.main
.run_svn(None, 'propset', 'prop', 'val', mu_path
)
2667 svntest
.main
.run_svn(None, 'propset', 'prop', 'val', D_path
)
2668 expected_output
= svntest
.wc
.State(wc_dir
, {
2669 'iota' : Item(verb
='Sending'),
2670 'A/mu': Item(verb
='Sending'),
2671 'A/B/lambda': Item(verb
='Sending'),
2672 'A/D': Item(verb
='Sending'),
2675 expected_status
.tweak('iota', 'A/mu', 'A/B/lambda', 'A/D', wc_rev
=2)
2676 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
2677 expected_status
, None,
2678 None, None, None, None, wc_dir
)
2680 # Do another change to each path that we will need later.
2681 # Also, change a file below A/D in the path.
2682 svntest
.main
.file_append(iota_path
, 'Another line for iota\n')
2683 svntest
.main
.file_append(mu_path
, 'Another line for mu\n')
2684 svntest
.main
.file_append(lambda_path
, 'Another line for lambda\n')
2685 svntest
.main
.run_svn(None, 'propset', 'prop', 'val2', D_path
)
2686 svntest
.main
.file_append(pi_path
, 'Another line for pi\n')
2687 expected_status
.tweak('iota', 'A/mu', 'A/B/lambda', 'A/D', 'A/D/G/pi',
2689 expected_output
.add({
2690 'A/D/G/pi': Item(verb
='Sending')})
2691 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
2692 expected_status
, None,
2693 None, None, None, None, wc_dir
)
2695 # Go back to revision 1.
2696 expected_output
= svntest
.wc
.State(wc_dir
, {
2697 'iota' : Item(status
='U '),
2698 'A/B/lambda' : Item(status
='UU'),
2699 'A/mu' : Item(status
='UU'),
2700 'A/D': Item(status
=' U'),
2701 'A/D/G/pi': Item(status
='U '),
2703 expected_disk
= svntest
.main
.greek_state
.copy()
2704 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2705 svntest
.actions
.run_and_verify_update(wc_dir
,
2714 # Create modifications conflicting with rev 2.
2715 svntest
.main
.file_append(iota_path
, 'Conflicting appended text for iota\n')
2716 svntest
.main
.run_svn(None, 'propset', 'prop', 'conflictval', lambda_path
)
2717 svntest
.main
.file_append(mu_path
, 'Conflicting appended text for mu\n')
2718 svntest
.main
.run_svn(None, 'propset', 'prop', 'conflictval', mu_path
)
2719 svntest
.main
.run_svn(None, 'propset', 'prop', 'conflictval', D_path
)
2721 # Update to revision 2, expecting conflicts.
2722 expected_output
= svntest
.wc
.State(wc_dir
, {
2723 'iota': Item(status
='C '),
2724 'A/B/lambda': Item(status
=' C'),
2725 'A/mu': Item(status
='CC'),
2726 'A/D': Item(status
=' C'),
2728 expected_disk
.tweak('iota',
2729 contents
="\n".join(["This is the file 'iota'.",
2731 "Conflicting appended text for iota",
2733 "Original appended text for iota",
2736 expected_disk
.tweak('A/mu',
2737 contents
="\n".join(["This is the file 'mu'.",
2739 "Conflicting appended text for mu",
2741 "Original appended text for mu",
2744 props
={'prop': 'conflictval'})
2745 expected_disk
.tweak('A/B/lambda', 'A/D', props
={'prop': 'conflictval'})
2747 expected_status
.tweak(wc_rev
=2)
2748 expected_status
.tweak('iota', status
='C ')
2749 expected_status
.tweak('A/B/lambda', 'A/D', status
=' C')
2750 expected_status
.tweak('A/mu', status
='CC')
2751 extra_files
= [ [wc_dir
, 'iota.*\.(r1|r2|mine)'],
2752 [wc_dir
, 'mu.*\.(r1|r2|mine|prej)'],
2753 [wc_dir
, 'lambda.*\.prej'],
2754 [wc_dir
, 'dir_conflicts.prej']]
2755 svntest
.actions
.run_and_verify_update(wc_dir
,
2760 detect_extra_files
, extra_files
,
2764 # Now, update to HEAD, which should skip all the conflicted files, but
2765 # still update the pi file.
2766 expected_output
= svntest
.wc
.State(wc_dir
, {
2767 'iota' : Item(verb
='Skipped'),
2768 'A/B/lambda' : Item(verb
='Skipped'),
2769 'A/mu' : Item(verb
='Skipped'),
2770 'A/D' : Item(verb
='Skipped'),
2771 'A/D/G/pi' : Item(status
='U '),
2773 expected_status
.tweak(wc_rev
=3)
2774 expected_status
.tweak('iota', 'A/B/lambda', 'A/mu', 'A/D', wc_rev
=2)
2775 expected_disk
.tweak('A/D/G/pi', contents
="""This is the file 'pi'.
2778 svntest
.actions
.run_and_verify_update(wc_dir
,
2783 detect_extra_files
, extra_files
,
2786 #----------------------------------------------------------------------
2787 def mergeinfo_update_elision(sbox
):
2788 "mergeinfo does not elide after update"
2790 # No mergeinfo elision is performed when doing updates. So updates may
2791 # result in equivalent mergeinfo on a path and it's nearest working copy
2792 # parent with explicit mergeinfo. This is currently permitted and
2793 # honestly we could probably do without this test(?).
2795 # Search for the comment entitled "The Merge Kluge" in merge_tests.py
2796 # to understand why we shorten, and subsequently chdir() after calling
2798 def shorten_path_kludge(path
):
2799 shorten_by
= len(svntest
.main
.work_dir
) + len(os
.sep
)
2800 return path
[shorten_by
:]
2803 wc_dir
= sbox
.wc_dir
2805 # Some paths we'll care about
2806 alpha_COPY_path
= os
.path
.join(wc_dir
, "A", "B_COPY", "E", "alpha")
2807 alpha_path
= os
.path
.join(wc_dir
, "A", "B", "E", "alpha")
2808 B_COPY_path
= os
.path
.join(wc_dir
, "A", "B_COPY")
2809 E_COPY_path
= os
.path
.join(wc_dir
, "A", "B_COPY", "E")
2810 beta_path
= os
.path
.join(wc_dir
, "A", "B", "E", "beta")
2811 lambda_path
= os
.path
.join(wc_dir
, "A", "B", "lambda")
2813 # Make a branch A/B_COPY
2814 svntest
.actions
.run_and_verify_svn(
2816 ["A " + os
.path
.join(wc_dir
, "A", "B_COPY", "lambda") + "\n",
2817 "A " + os
.path
.join(wc_dir
, "A", "B_COPY", "E") + "\n",
2818 "A " + os
.path
.join(wc_dir
, "A", "B_COPY", "E", "alpha") + "\n",
2819 "A " + os
.path
.join(wc_dir
, "A", "B_COPY", "E", "beta") + "\n",
2820 "A " + os
.path
.join(wc_dir
, "A", "B_COPY", "F") + "\n",
2821 "Checked out revision 1.\n",
2822 "A " + B_COPY_path
+ "\n"],
2825 sbox
.repo_url
+ "/A/B",
2828 expected_output
= wc
.State(wc_dir
, {'A/B_COPY' : Item(verb
='Adding')})
2829 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2830 expected_status
.add({
2831 "A/B_COPY" : Item(status
=' ', wc_rev
=2),
2832 "A/B_COPY/lambda" : Item(status
=' ', wc_rev
=2),
2833 "A/B_COPY/E" : Item(status
=' ', wc_rev
=2),
2834 "A/B_COPY/E/alpha" : Item(status
=' ', wc_rev
=2),
2835 "A/B_COPY/E/beta" : Item(status
=' ', wc_rev
=2),
2836 "A/B_COPY/F" : Item(status
=' ', wc_rev
=2),})
2838 svntest
.actions
.run_and_verify_commit(wc_dir
,
2842 None, None, None, None,
2845 # Make some changes under A/B
2847 # r3 - modify and commit A/B/E/beta
2848 svntest
.main
.file_write(beta_path
, "New content")
2849 expected_output
= wc
.State(wc_dir
, {'A/B/E/beta' : Item(verb
='Sending')})
2850 expected_status
.tweak('A/B/E/beta', wc_rev
=3)
2851 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
2852 expected_status
, None, None, None,
2855 # r4 - modify and commit A/B/lambda
2856 svntest
.main
.file_write(lambda_path
, "New content")
2857 expected_output
= wc
.State(wc_dir
, {'A/B/lambda' : Item(verb
='Sending')})
2858 expected_status
.tweak('A/B/lambda', wc_rev
=4)
2859 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
2860 expected_status
, None, None, None,
2863 # r5 - modify and commit A/B/E/alpha
2864 svntest
.main
.file_write(alpha_path
, "New content")
2865 expected_output
= wc
.State(wc_dir
, {'A/B/E/alpha' : Item(verb
='Sending')})
2866 expected_status
.tweak('A/B/E/alpha', wc_rev
=5)
2867 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
2868 expected_status
, None, None, None,
2871 # Merge r2:5 into A/B_COPY
2872 # Search for the comment entitled "The Merge Kluge" in merge_tests.py,
2873 # to understand why we shorten and chdir() below.
2874 short_B_COPY_path
= shorten_path_kludge(B_COPY_path
)
2875 expected_output
= wc
.State(short_B_COPY_path
, {
2876 'lambda' : Item(status
='U '),
2877 'E/alpha' : Item(status
='U '),
2878 'E/beta' : Item(status
='U '),
2880 expected_merge_status
= wc
.State(short_B_COPY_path
, {
2881 '' : Item(status
=' M', wc_rev
=2),
2882 'lambda' : Item(status
='M ', wc_rev
=2),
2883 'E' : Item(status
=' ', wc_rev
=2),
2884 'E/alpha' : Item(status
='M ', wc_rev
=2),
2885 'E/beta' : Item(status
='M ', wc_rev
=2),
2886 'F' : Item(status
=' ', wc_rev
=2),
2888 expected_merge_disk
= wc
.State('', {
2889 '' : Item(props
={SVN_PROP_MERGE_INFO
: '/A/B:3-5'}),
2890 'lambda' : Item("New content"),
2892 'E/alpha' : Item("New content"),
2893 'E/beta' : Item("New content"),
2896 expected_skip
= wc
.State(short_B_COPY_path
, { })
2897 saved_cwd
= os
.getcwd()
2899 os
.chdir(svntest
.main
.work_dir
)
2900 svntest
.actions
.run_and_verify_merge(short_B_COPY_path
, '2', '5',
2904 expected_merge_disk
,
2905 expected_merge_status
,
2907 None, None, None, None,
2911 # r6 - Commit the merge
2912 expected_output
= wc
.State(wc_dir
,
2913 {'A/B_COPY' : Item(verb
='Sending'),
2914 'A/B_COPY/E/alpha' : Item(verb
='Sending'),
2915 'A/B_COPY/E/beta' : Item(verb
='Sending'),
2916 'A/B_COPY/lambda' : Item(verb
='Sending')})
2917 expected_status
.tweak('A/B_COPY', wc_rev
=6)
2918 expected_status
.tweak('A/B_COPY/E/alpha', wc_rev
=6)
2919 expected_status
.tweak('A/B_COPY/E/beta', wc_rev
=6)
2920 expected_status
.tweak('A/B_COPY/lambda', wc_rev
=6)
2921 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
2922 expected_status
, None, None, None,
2925 # Update WC back to r5, A/COPY_B is at it's pre-merge state again
2926 expected_output
= wc
.State(wc_dir
,
2927 {'A/B_COPY' : Item(status
=' U'),
2928 'A/B_COPY/E/alpha' : Item(status
='U '),
2929 'A/B_COPY/E/beta' : Item(status
='U '),
2930 'A/B_COPY/lambda' : Item(status
='U '),})
2931 expected_status
.tweak(wc_rev
=5)
2932 expected_disk
= svntest
.main
.greek_state
.copy()
2934 'A/B_COPY' : Item(props
={SVN_PROP_MERGE_INFO
: ''}),
2935 'A/B_COPY/lambda' : Item("This is the file 'lambda'.\n"),
2936 'A/B_COPY/E' : Item(),
2937 'A/B_COPY/E/alpha' : Item("This is the file 'alpha'.\n"),
2938 'A/B_COPY/E/beta' : Item("This is the file 'beta'.\n"),
2939 'A/B_COPY/F' : Item(),
2941 expected_disk
.tweak('A/B/lambda', contents
="New content")
2942 expected_disk
.tweak('A/B/E/alpha', contents
="New content")
2943 expected_disk
.tweak('A/B/E/beta', contents
="New content")
2944 svntest
.actions
.run_and_verify_update(wc_dir
,
2952 # Merge r2:5 to A/B_COPY/E/alpha
2953 short_alpha_COPY_path
= shorten_path_kludge(alpha_COPY_path
)
2954 expected_output
= wc
.State(short_alpha_COPY_path
, {
2955 'alpha' : Item(status
='U '),
2957 expected_skip
= wc
.State(short_alpha_COPY_path
, { })
2958 saved_cwd
= os
.getcwd()
2960 os
.chdir(svntest
.main
.work_dir
)
2961 # run_and_verify_merge doesn't support merging to a file WCPATH
2962 # so use run_and_verify_svn.
2963 update_line
= 'U ' + short_alpha_COPY_path
+ '\n'
2964 if sys
.platform
== 'win32':
2965 # Construct a properly escaped regex when dealing with
2966 # '\' riddled paths on Windows.
2967 update_line
= update_line
.replace("\\", "\\\\")
2968 svntest
.actions
.run_and_verify_svn(None,
2970 [svntest
.main
.merge_notify_line(3, 5),
2972 [], 'merge', '-r2:5',
2973 sbox
.repo_url
+ '/A/B/E/alpha',
2974 short_alpha_COPY_path
)
2978 expected_alpha_status
= wc
.State(alpha_COPY_path
, {
2979 '' : Item(status
='MM', wc_rev
=5),
2981 svntest
.actions
.run_and_verify_status(alpha_COPY_path
,
2982 expected_alpha_status
)
2984 svntest
.actions
.run_and_verify_svn(None, ["/A/B/E/alpha:3-5\n"], [],
2985 'propget', SVN_PROP_MERGE_INFO
,
2988 # Update WC. The local mergeinfo (r3-5) on A/B_COPY/E/alpha is
2989 # identical to that on added to A/B_COPY by the update, but update
2990 # doesn't support elision so this redundancy is permitted.
2991 expected_output
= wc
.State(wc_dir
, {
2992 'A/B_COPY/lambda' : Item(status
='U '),
2993 'A/B_COPY/E/alpha' : Item(status
='G '),
2994 'A/B_COPY/E/beta' : Item(status
='U '),
2995 'A/B_COPY' : Item(status
=' U'),
2997 expected_disk
.tweak('A/B_COPY', props
={SVN_PROP_MERGE_INFO
: '/A/B:3-5'})
2998 expected_disk
.tweak('A/B_COPY/lambda', contents
="New content")
2999 expected_disk
.tweak('A/B_COPY/E/beta', contents
="New content")
3000 expected_disk
.tweak('A/B_COPY/E/alpha', contents
="New content",
3001 props
={SVN_PROP_MERGE_INFO
: '/A/B/E/alpha:3-5'})
3002 expected_status
.tweak(wc_rev
=6)
3003 expected_status
.tweak('A/B_COPY/E/alpha', status
=' M')
3004 svntest
.actions
.run_and_verify_update(wc_dir
,
3011 # Now test that an updated target's mergeinfo can itself elide.
3012 # r7 - modify and commit A/B/E/alpha
3013 svntest
.main
.file_write(alpha_path
, "More new content")
3014 expected_output
= wc
.State(wc_dir
, {
3015 'A/B/E/alpha' : Item(verb
='Sending'),
3016 'A/B_COPY/E/alpha' : Item(verb
='Sending')})
3017 expected_status
.tweak('A/B/E/alpha', 'A/B_COPY/E/alpha', status
=' ',
3019 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
3020 expected_status
, None, None, None,
3023 # Merge r6:7 into A/B_COPY/E
3024 short_E_COPY_path
= shorten_path_kludge(E_COPY_path
)
3025 expected_output
= wc
.State(short_E_COPY_path
, {
3026 'alpha' : Item(status
='U '),
3028 expected_merge_status
= wc
.State(short_E_COPY_path
, {
3029 '' : Item(status
=' M', wc_rev
=6),
3030 'alpha' : Item(status
='MM', wc_rev
=7),
3031 'beta' : Item(status
=' ', wc_rev
=6),
3033 expected_merge_disk
= wc
.State('', {
3034 '' : Item(props
={SVN_PROP_MERGE_INFO
: '/A/B/E:3-5,7'}),
3035 'alpha' : Item("More new content"),
3036 'beta' : Item("New content"),
3038 expected_skip
= wc
.State(short_E_COPY_path
, { })
3039 saved_cwd
= os
.getcwd()
3041 os
.chdir(svntest
.main
.work_dir
)
3042 svntest
.actions
.run_and_verify_merge(short_E_COPY_path
, '6', '7',
3046 expected_merge_disk
,
3047 expected_merge_status
,
3049 None, None, None, None,
3054 # r8 - Commit the merge
3055 svntest
.actions
.run_and_verify_svn(None,
3056 ["At revision 7.\n"],
3057 [], 'update', wc_dir
)
3058 expected_output
= wc
.State(wc_dir
,
3059 {'A/B_COPY/E' : Item(verb
='Sending'),
3060 'A/B_COPY/E/alpha' : Item(verb
='Sending')})
3061 expected_status
.tweak(wc_rev
=7)
3062 expected_status
.tweak('A/B_COPY/E', 'A/B_COPY/E/alpha', wc_rev
=8)
3063 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
3064 expected_status
, None, None, None,
3067 # Update A/COPY_B/E back to r7
3068 expected_output
= wc
.State(wc_dir
, {
3069 'A/B_COPY/E/alpha' : Item(status
='UU'),
3070 'A/B_COPY/E' : Item(status
=' U'),
3072 expected_status
.tweak(wc_rev
=7)
3073 expected_disk
.tweak('A/B_COPY',
3074 props
={SVN_PROP_MERGE_INFO
: '/A/B:3-5'})
3075 expected_disk
.tweak('A/B/E/alpha', contents
="More new content")
3076 expected_disk
.tweak('A/B_COPY/E/alpha', contents
="New content")
3078 svntest
.actions
.run_and_verify_update(wc_dir
,
3084 '-r', '7', E_COPY_path
)
3086 # Merge r6:7 to A/B_COPY
3087 short_B_COPY_path
= shorten_path_kludge(B_COPY_path
)
3088 expected_output
= wc
.State(short_B_COPY_path
, {
3089 'E/alpha' : Item(status
='U '),
3091 expected_merge_status
= wc
.State(short_B_COPY_path
, {
3092 '' : Item(status
=' M', wc_rev
=7),
3093 'lambda' : Item(status
=' ', wc_rev
=7),
3094 'E' : Item(status
=' ', wc_rev
=7),
3095 'E/alpha' : Item(status
='MM', wc_rev
=7),
3096 'E/beta' : Item(status
=' ', wc_rev
=7),
3097 'F' : Item(status
=' ', wc_rev
=7),
3099 expected_merge_disk
= wc
.State('', {
3100 '' : Item(props
={SVN_PROP_MERGE_INFO
: '/A/B:3-5,7'}),
3101 'lambda' : Item("New content"),
3103 'E/alpha' : Item("More new content"),
3104 'E/beta' : Item("New content"),
3107 expected_skip
= wc
.State(short_B_COPY_path
, { })
3108 saved_cwd
= os
.getcwd()
3110 os
.chdir(svntest
.main
.work_dir
)
3111 svntest
.actions
.run_and_verify_merge(short_B_COPY_path
, '6', '7',
3115 expected_merge_disk
,
3116 expected_merge_status
,
3118 None, None, None, None,
3119 None, 1,alpha_COPY_path
)
3123 # Update just A/B_COPY/E. The mergeinfo (r3-5,7) reset on
3124 # A/B_COPY/E by the udpate is identical to the local info on
3125 # A/B_COPY, so should elide, leaving no mereginfo on E.
3126 #expected_output = svntest.wc.State(wc_dir, { })
3127 expected_output
= wc
.State(wc_dir
, {
3128 'A/B_COPY/E/alpha' : Item(status
='GG'),
3129 'A/B_COPY/E/' : Item(status
=' U'),
3131 expected_status
.tweak('A/B_COPY', status
=' M', wc_rev
=7)
3132 expected_status
.tweak('A/B_COPY/E', status
=' ', wc_rev
=8)
3133 expected_status
.tweak('A/B_COPY/E/alpha', wc_rev
=8)
3134 expected_status
.tweak('A/B_COPY/E/beta', wc_rev
=8)
3135 expected_disk
.tweak('A/B_COPY',
3136 props
={SVN_PROP_MERGE_INFO
: '/A/B:3-5,7'})
3137 expected_disk
.tweak('A/B_COPY/E',
3138 props
={SVN_PROP_MERGE_INFO
: '/A/B/E:3-5,7'})
3139 expected_disk
.tweak('A/B_COPY/E/alpha', contents
="More new content",
3141 svntest
.actions
.run_and_verify_update(wc_dir
,
3146 None, None, 1, E_COPY_path
)
3149 #----------------------------------------------------------------------
3150 # If the update editor receives add_file(foo, copyfrom='blah'), it
3151 # should attempt to locate 'blah' in the wc, and then copy it into place.
3153 def update_handles_copyfrom(sbox
):
3154 "update should make use of copyfrom args"
3157 wc_dir
= sbox
.wc_dir
3159 # Make a backup copy of the working copy.
3160 wc_backup
= sbox
.add_wc_path('backup')
3161 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
3163 # Copy 'rho' to 'glub'
3164 rho_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'rho')
3165 glub_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'glub')
3166 svntest
.actions
.run_and_verify_svn(None, None, [],
3167 'copy', rho_path
, glub_path
)
3169 # Commit that change, creating r2.
3170 expected_output
= svntest
.wc
.State(wc_dir
, {
3171 'A/D/G/glub' : Item(verb
='Adding'),
3173 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3174 expected_status
.add({
3175 'A/D/G/glub' : Item(status
=' ', wc_rev
=2),
3177 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
3178 expected_status
, None,
3179 None, None, None, None, wc_dir
)
3181 # Make a local edits to rho in the backup working copy - both text and props
3182 rho2_path
= os
.path
.join(wc_backup
, 'A', 'D', 'G', 'rho')
3183 svntest
.main
.file_append(rho2_path
, "Some new text.\n")
3184 svntest
.main
.run_svn(None, 'propset', 'Kubla', 'Khan', rho2_path
)
3186 # Now try updating our backup working copy: it should receive glub,
3187 # but with copyfrom args of rho@1, and thus copy the existing
3188 # (edited) rho to glub. In other words, both rho and glub should be
3189 # identical and contain the same local edits.
3191 expected_output
= svntest
.wc
.State(wc_backup
, { })
3192 expected_output
= wc
.State(wc_backup
, {
3193 'A/D/G/glub' : Item(status
='A '), ### perhaps update should show 'A +' ??
3196 expected_disk
= svntest
.main
.greek_state
.copy()
3197 expected_disk
.tweak('A/D/G/rho',
3198 contents
="This is the file 'rho'.\nSome new text.\n",
3199 props
={'Kubla' : 'Khan'})
3201 'A/D/G/glub' : Item("This is the file 'rho'.\nSome new text.\n",
3202 props
={'Kubla' : 'Khan', 'svn:mergeinfo' : ''})
3205 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 2)
3206 expected_status
.tweak('A/D/G/rho', wc_rev
=2, status
='MM')
3207 expected_status
.add({
3208 'A/D/G/glub' : Item(status
='MM', wc_rev
=2),
3210 svntest
.actions
.run_and_verify_update(wc_backup
,
3216 #----------------------------------------------------------------------
3217 # if the update_editor receives add_file(copyfrom=...), and the
3218 # copyfrom_path simply isn't available in the working copy, it should
3219 # fall back to doing an RA request to fetch the file.
3221 def copyfrom_degrades_gracefully(sbox
):
3222 "update degrades well if copyfrom_path unavailable"
3225 wc_dir
= sbox
.wc_dir
3227 # Make a backup copy of the working copy.
3228 wc_backup
= sbox
.add_wc_path('backup')
3229 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
3231 # Move 'alpha' to 'glub'
3232 alpha_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'alpha')
3233 glub_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'glub')
3234 svntest
.actions
.run_and_verify_svn(None, None, [],
3235 'mv', alpha_path
, glub_path
)
3237 # Commit that change, creating r2.
3238 expected_output
= svntest
.wc
.State(wc_dir
, {
3239 'A/B/E/alpha' : Item(verb
='Deleting'),
3240 'A/D/G/glub' : Item(verb
='Adding'),
3242 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3243 expected_status
.add({
3244 'A/D/G/glub' : Item(status
=' ', wc_rev
=2),
3246 expected_status
.remove('A/B/E/alpha')
3247 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
3248 expected_status
, None,
3249 None, None, None, None, wc_dir
)
3251 # In the 2nd working copy, update just one side of the move -- so that
3252 # alpha gets deleted, but glub not yet added.
3253 E_path
= os
.path
.join(wc_backup
, 'A', 'B', 'E')
3254 expected_output
= svntest
.wc
.State(E_path
, {
3255 'alpha' : Item(status
='D '),
3257 expected_disk
= wc
.State('', {
3258 'beta' : wc
.StateItem("This is the file 'beta'.\n"),
3260 expected_status
= svntest
.wc
.State(E_path
, {
3261 '' : Item(status
=' '),
3262 'beta' : Item(status
=' '),
3264 expected_status
.tweak(wc_rev
=2)
3265 svntest
.actions
.run_and_verify_update(E_path
,
3270 # Now update the entire working copy, which should cause an
3271 # add_file(glub, copyfrom_path=alpha)... except alpha is already gone.
3272 # Update editor should gracefully fetch it via RA request.
3273 expected_output
= svntest
.wc
.State(wc_backup
, { })
3274 expected_output
= wc
.State(wc_backup
, {
3275 'A/D/G/glub' : Item(status
='A '),
3277 expected_disk
= svntest
.main
.greek_state
.copy()
3278 expected_disk
.remove('A/B/E/alpha')
3280 'A/D/G/glub' : Item("This is the file 'alpha'.\n"),
3282 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 2)
3283 expected_status
.remove('A/B/E/alpha')
3284 expected_status
.add({
3285 'A/D/G/glub' : Item(status
=' ', wc_rev
=2),
3287 svntest
.actions
.run_and_verify_update(wc_backup
,
3292 #----------------------------------------------------------------------
3293 # If the update editor receives add_file(foo, copyfrom='blah'), it
3294 # should attempt to locate 'blah' in the wc, and then copy it into
3295 # place. Furthermore, the new file should be able to receive
3296 # subsequent txdeltas coming from the server.
3298 def update_handles_copyfrom_with_txdeltas(sbox
):
3299 "update uses copyfrom & accepts further txdeltas"
3302 wc_dir
= sbox
.wc_dir
3304 # Make a backup copy of the working copy.
3305 wc_backup
= sbox
.add_wc_path('backup')
3306 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
3308 # Copy 'rho' to 'glub'
3309 rho_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'rho')
3310 glub_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'glub')
3311 svntest
.actions
.run_and_verify_svn(None, None, [],
3312 'copy', rho_path
, glub_path
)
3314 # Commit that change, creating r2.
3315 expected_output
= svntest
.wc
.State(wc_dir
, {
3316 'A/D/G/glub' : Item(verb
='Adding'),
3318 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3319 expected_status
.add({
3320 'A/D/G/glub' : Item(status
=' ', wc_rev
=2),
3322 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
3323 expected_status
, None,
3324 None, None, None, None, wc_dir
)
3326 # Make additional edits to glub...
3327 svntest
.main
.file_append_binary(glub_path
, "Some new text.\n")
3328 svntest
.main
.run_svn(None, 'propset', 'Kubla', 'Khan', glub_path
)
3330 # Commit the changes, creating r3.
3331 expected_output
= svntest
.wc
.State(wc_dir
, {
3332 'A/D/G/glub' : Item(verb
='Sending'),
3334 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3335 expected_status
.add({
3336 'A/D/G/glub' : Item(status
=' ', wc_rev
=3),
3338 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
3339 expected_status
, None,
3340 None, None, None, None, wc_dir
)
3342 # Make a local edit to rho in the backup working copy.
3343 rho2_path
= os
.path
.join(wc_backup
, 'A', 'D', 'G', 'rho')
3344 svntest
.main
.file_write(rho2_path
,
3345 "New first line.\nThis is the file 'rho'.\n",
3348 # Now try updating our backup working copy: it should receive glub,
3349 # but with copyfrom args of rho@1, and thus copy the existing rho to
3350 # glub. Furthermore, it should then apply the extra r3 edits to the
3353 expected_output
= svntest
.wc
.State(wc_backup
, { })
3354 expected_output
= wc
.State(wc_backup
, {
3355 'A/D/G/glub' : Item(status
='A '), ### perhaps update should show 'A +' ??
3358 expected_disk
= svntest
.main
.greek_state
.copy()
3359 expected_disk
.tweak('A/D/G/rho',
3360 contents
="New first line.\nThis is the file 'rho'.\n")
3362 'A/D/G/glub' : Item("New first line.\nThis is the file 'rho'.\nSome new text.\n",
3363 props
={'Kubla' : 'Khan', 'svn:mergeinfo' : ''})
3366 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 3)
3367 expected_status
.tweak('A/D/G/rho', wc_rev
=3, status
='M ')
3368 expected_status
.add({
3369 'A/D/G/glub' : Item(status
='M ', wc_rev
=3),
3371 svntest
.actions
.run_and_verify_update(wc_backup
,
3377 #----------------------------------------------------------------------
3378 # Very obscure bug: Issue #2977.
3379 # Let's say there's a revision with
3383 # and a later revision that modifies b. We then try a fresh checkout. If
3384 # the server happens to send us 'b' first, then when it later gets 'c'
3385 # (with a copyfrom of 'b') it might try to use the 'b' in the wc as the
3386 # copyfrom base. This is wrong, because 'b' was changed later; however,
3387 # due to a bug, the setting of svn:entry:committed-rev on 'b' is not being
3388 # properly seen by the client, and it chooses the wrong base. Corruption!
3390 # Note that because this test depends on the order that the server sends
3391 # changes, it is very fragile; even changing the file names can avoid
3392 # triggering the bug.
3394 def update_copied_from_replaced_and_changed(sbox
):
3395 "update chooses right copyfrom for double move"
3398 wc_dir
= sbox
.wc_dir
3400 fn1_relpath
= os
.path
.join('A', 'B', 'E', 'aardvark')
3401 fn2_relpath
= os
.path
.join('A', 'B', 'E', 'alpha')
3402 fn3_relpath
= os
.path
.join('A', 'B', 'E', 'beta')
3403 fn1_path
= os
.path
.join(wc_dir
, fn1_relpath
)
3404 fn2_path
= os
.path
.join(wc_dir
, fn2_relpath
)
3405 fn3_path
= os
.path
.join(wc_dir
, fn3_relpath
)
3408 svntest
.actions
.run_and_verify_svn(None, None, [],
3409 'mv', fn2_path
, fn1_path
)
3412 svntest
.actions
.run_and_verify_svn(None, None, [],
3413 'mv', fn3_path
, fn2_path
)
3415 # Commit that change, creating r2.
3416 expected_output
= svntest
.wc
.State(wc_dir
, {
3417 fn1_relpath
: Item(verb
='Adding'),
3418 fn2_relpath
: Item(verb
='Replacing'),
3419 fn3_relpath
: Item(verb
='Deleting'),
3421 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3422 expected_status
.remove(fn2_relpath
, fn3_relpath
)
3423 expected_status
.add({
3424 fn1_relpath
: Item(status
=' ', wc_rev
=2),
3425 fn2_relpath
: Item(status
=' ', wc_rev
=2),
3427 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
3428 expected_status
, None,
3429 None, None, None, None, wc_dir
)
3432 fn2_final_contents
= "I have new contents for the middle file."
3433 svntest
.main
.file_write(fn2_path
, fn2_final_contents
)
3435 # Commit the changes, creating r3.
3436 expected_output
= svntest
.wc
.State(wc_dir
, {
3437 fn2_relpath
: Item(verb
='Sending'),
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
=3),
3445 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
3446 expected_status
, None,
3447 None, None, None, None, wc_dir
)
3450 expected_output
= svntest
.wc
.State(wc_dir
, {
3451 fn1_relpath
: Item(status
='D '),
3452 fn2_relpath
: Item(status
='A '), # though actually should be D and A
3453 fn3_relpath
: Item(status
='A '),
3455 # Create expected disk tree for the update to rev 0
3456 expected_disk
= svntest
.main
.greek_state
.copy()
3457 # Do the update and check the results.
3458 svntest
.actions
.run_and_verify_update(wc_dir
,
3462 None, None, None, None, 0,
3465 # And back up to 3 again.
3466 expected_output
= svntest
.wc
.State(wc_dir
, {
3467 fn1_relpath
: Item(status
='A '),
3468 fn2_relpath
: Item(status
='A '), # though actually should be D and A
3469 fn3_relpath
: Item(status
='D '),
3471 # Create expected disk tree for the update to rev 0
3472 expected_disk
= svntest
.main
.greek_state
.copy()
3474 fn1_relpath
: Item("This is the file 'alpha'.\n"),
3476 expected_disk
.tweak(fn2_relpath
, contents
=fn2_final_contents
)
3477 expected_disk
.remove(fn3_relpath
)
3478 # reuse old expected_status, but at r3
3479 expected_status
.tweak(wc_rev
=3)
3480 svntest
.actions
.run_and_verify_update(wc_dir
,
3483 expected_status
, None,
3484 None, None, None, None, 0,
3488 #----------------------------------------------------------------------
3491 def update_accept_conflicts(sbox
):
3492 "update --accept automatic conflict resolution"
3495 wc_dir
= sbox
.wc_dir
3497 # Make a backup copy of the working copy
3498 wc_backup
= sbox
.add_wc_path('backup')
3499 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
3501 # Make a few local mods to files which will be committed
3502 iota_path
= os
.path
.join(wc_dir
, 'iota')
3503 lambda_path
= os
.path
.join(wc_dir
, 'A', 'B', 'lambda')
3504 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
3505 alpha_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'alpha')
3506 beta_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'beta')
3507 pi_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'pi')
3508 rho_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'rho')
3509 svntest
.main
.file_append(lambda_path
, 'Their appended text for lambda\n')
3510 svntest
.main
.file_append(iota_path
, 'Their appended text for iota\n')
3511 svntest
.main
.file_append(mu_path
, 'Their appended text for mu\n')
3512 svntest
.main
.file_append(alpha_path
, 'Their appended text for alpha\n')
3513 svntest
.main
.file_append(beta_path
, 'Their appended text for beta\n')
3514 svntest
.main
.file_append(pi_path
, 'Their appended text for pi\n')
3515 svntest
.main
.file_append(rho_path
, 'Their appended text for rho\n')
3517 # Make a few local mods to files which will be conflicted
3518 iota_path_backup
= os
.path
.join(wc_backup
, 'iota')
3519 lambda_path_backup
= os
.path
.join(wc_backup
, 'A', 'B', 'lambda')
3520 mu_path_backup
= os
.path
.join(wc_backup
, 'A', 'mu')
3521 alpha_path_backup
= os
.path
.join(wc_backup
, 'A', 'B', 'E', 'alpha')
3522 beta_path_backup
= os
.path
.join(wc_backup
, 'A', 'B', 'E', 'beta')
3523 pi_path_backup
= os
.path
.join(wc_backup
, 'A', 'D', 'G', 'pi')
3524 rho_path_backup
= os
.path
.join(wc_backup
, 'A', 'D', 'G', 'rho')
3525 svntest
.main
.file_append(iota_path_backup
,
3526 'My appended text for iota\n')
3527 svntest
.main
.file_append(lambda_path_backup
,
3528 'My appended text for lambda\n')
3529 svntest
.main
.file_append(mu_path_backup
,
3530 'My appended text for mu\n')
3531 svntest
.main
.file_append(alpha_path_backup
,
3532 'My appended text for alpha\n')
3533 svntest
.main
.file_append(beta_path_backup
,
3534 'My appended text for beta\n')
3535 svntest
.main
.file_append(pi_path_backup
,
3536 'My appended text for pi\n')
3537 svntest
.main
.file_append(rho_path_backup
,
3538 'My appended text for rho\n')
3540 # Created expected output tree for 'svn ci'
3541 expected_output
= svntest
.wc
.State(wc_dir
, {
3542 'iota' : Item(verb
='Sending'),
3543 'A/B/lambda' : Item(verb
='Sending'),
3544 'A/mu' : Item(verb
='Sending'),
3545 'A/B/E/alpha': Item(verb
='Sending'),
3546 'A/B/E/beta': Item(verb
='Sending'),
3547 'A/D/G/pi' : Item(verb
='Sending'),
3548 'A/D/G/rho' : Item(verb
='Sending'),
3551 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3552 expected_status
.tweak('iota', wc_rev
=2)
3553 expected_status
.tweak('A/B/lambda', wc_rev
=2)
3554 expected_status
.tweak('A/mu', wc_rev
=2)
3555 expected_status
.tweak('A/B/E/alpha', wc_rev
=2)
3556 expected_status
.tweak('A/B/E/beta', wc_rev
=2)
3557 expected_status
.tweak('A/D/G/pi', wc_rev
=2)
3558 expected_status
.tweak('A/D/G/rho', wc_rev
=2)
3561 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
3562 expected_status
, None,
3563 None, None, None, None, wc_dir
)
3565 # Now we'll update each of our 5 files in wc_backup; each one will get
3566 # conflicts, and we'll handle each with a different --accept option.
3568 # Setup SVN_EDITOR and SVN_MERGE for --accept={edit,launch}.
3569 svntest
.main
.use_editor('append_foo')
3571 # iota: no accept option
3572 # Just leave the conflicts alone, since run_and_verify_svn already uses
3573 # the --non-interactive option.
3574 svntest
.actions
.run_and_verify_svn(None,
3575 ['C %s\n' % (iota_path_backup
,),
3576 'Updated to revision 2.\n'],
3578 'update', iota_path_backup
)
3580 # lambda: --accept=postpone
3581 # Just leave the conflicts alone.
3582 svntest
.actions
.run_and_verify_svn(None,
3583 ['C %s\n' % (lambda_path_backup
,),
3584 'Updated to revision 2.\n'],
3586 'update', '--accept=postpone',
3590 # Accept the pre-update base file.
3591 svntest
.actions
.run_and_verify_svn(None,
3592 ['G %s\n' % (mu_path_backup
,),
3593 'Updated to revision 2.\n'],
3595 'update', '--accept=base',
3598 # alpha: --accept=mine
3599 # Accept the user's working file.
3600 svntest
.actions
.run_and_verify_svn(None,
3601 ['G %s\n' % (alpha_path_backup
,),
3602 'Updated to revision 2.\n'],
3604 'update', '--accept=mine',
3607 # beta: --accept=theirs
3608 # Accept their file.
3609 svntest
.actions
.run_and_verify_svn(None,
3610 ['G %s\n' % (beta_path_backup
,),
3611 'Updated to revision 2.\n'],
3613 'update', '--accept=theirs',
3617 # Run editor and accept the edited file.
3618 svntest
.actions
.run_and_verify_svn(None,
3619 ['G %s\n' % (pi_path_backup
,),
3620 'Updated to revision 2.\n'],
3622 'update', '--accept=edit',
3625 # rho: --accept=launch
3626 # Run SVN_MERGE and accept the merged file.
3627 svntest
.actions
.run_and_verify_svn(None,
3628 ['G %s\n' % (rho_path_backup
,),
3629 'Updated to revision 2.\n'],
3631 'update', '--accept=launch',
3634 # Set the expected disk contents for the test
3635 expected_disk
= svntest
.main
.greek_state
.copy()
3637 expected_disk
.tweak('iota', contents
=("This is the file 'iota'.\n"
3639 'My appended text for iota\n'
3641 'Their appended text for iota\n'
3643 expected_disk
.tweak('A/B/lambda', contents
=("This is the file 'lambda'.\n"
3645 'My appended text for lambda\n'
3647 'Their appended text for lambda\n'
3649 expected_disk
.tweak('A/mu', contents
="This is the file 'mu'.\n")
3650 expected_disk
.tweak('A/B/E/alpha', contents
=("This is the file 'alpha'.\n"
3651 'My appended text for alpha\n'))
3652 expected_disk
.tweak('A/B/E/beta', contents
=("This is the file 'beta'.\n"
3653 'Their appended text for beta\n'))
3654 expected_disk
.tweak('A/D/G/pi', contents
=("This is the file 'pi'.\n"
3656 'My appended text for pi\n'
3658 'Their appended text for pi\n'
3661 expected_disk
.tweak('A/D/G/rho', contents
=("This is the file 'rho'.\n"
3663 'My appended text for rho\n'
3665 'Their appended text for rho\n'
3669 # Set the expected extra files for the test
3670 extra_files
= ['iota.*\.r1', 'iota.*\.r2', 'iota.*\.mine',
3671 'lambda.*\.r1', 'lambda.*\.r2', 'lambda.*\.mine']
3673 # Set the expected status for the test
3674 expected_status
= svntest
.actions
.get_virginal_state(wc_backup
, 2)
3675 expected_status
.tweak('iota', 'A/B/lambda', 'A/mu',
3676 'A/B/E/alpha', 'A/B/E/beta',
3677 'A/D/G/pi', 'A/D/G/rho', wc_rev
=2)
3678 expected_status
.tweak('iota', status
='C ')
3679 expected_status
.tweak('A/B/lambda', status
='C ')
3680 expected_status
.tweak('A/mu', status
='M ')
3681 expected_status
.tweak('A/B/E/alpha', status
='M ')
3682 expected_status
.tweak('A/B/E/beta', status
=' ')
3683 expected_status
.tweak('A/D/G/pi', status
='M ')
3684 expected_status
.tweak('A/D/G/rho', status
='M ')
3686 # Set the expected output for the test
3687 expected_output
= wc
.State(wc_backup
, {})
3689 # Do the update and check the results in three ways.
3690 svntest
.actions
.run_and_verify_update(wc_backup
,
3695 svntest
.tree
.detect_conflict_files
,
3698 # Test for a wc corruption race condition (possibly introduced in
3699 # r23342) which is easy to trigger if interactive conflict resolution
3700 # dies in the middle of prompting. Specifically, we run an update
3701 # with interactive-conflicts on but close stdin immediately, so the
3702 # prompt errors out; then the dir_baton pool cleanup handlers in the
3703 # WC update editor flush and run incomplete logs and lead to WC
3704 # corruption, detectable by another update command.
3706 def eof_in_interactive_conflict_resolver(sbox
):
3707 "eof in interactive resolution can't break wc"
3710 wc_dir
= sbox
.wc_dir
3712 # Set up a custom config directory which *doesn't* turn off
3713 # interactive resolution
3714 config_contents
= '''\
3716 interactive-conflicts = true
3718 tmp_dir
= os
.path
.abspath(svntest
.main
.temp_dir
)
3719 config_dir
= os
.path
.join(tmp_dir
, 'interactive-conflicts-config')
3720 svntest
.main
.create_config_dir(config_dir
, config_contents
)
3722 iota_path
= os
.path
.join(wc_dir
, 'iota')
3724 # Modify iota and commit for r2.
3725 svntest
.main
.file_append(iota_path
, "Appended text in r2.\n")
3726 expected_output
= svntest
.wc
.State(wc_dir
, {
3727 'iota': Item(verb
="Sending"),
3729 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3730 expected_status
.tweak('iota', wc_rev
=2)
3731 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
3732 expected_status
, None,
3733 None, None, None, None, wc_dir
)
3735 # Go back to revision 1.
3736 expected_output
= svntest
.wc
.State(wc_dir
, {
3737 'iota' : Item(status
='U '),
3739 expected_disk
= svntest
.main
.greek_state
.copy()
3740 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3741 svntest
.actions
.run_and_verify_update(wc_dir
,
3750 # Modify iota differently and try to update *with the interactive
3751 # resolver*. ### The parser won't go so well with the output
3752 svntest
.main
.file_append(iota_path
, "Local mods to r1 text.\n")
3753 svntest
.actions
.run_and_verify_update(wc_dir
, None, None, None,
3754 "Can't read stdin: End of file found",
3755 None, None, None, None, 1,
3756 wc_dir
, '--config-dir', config_dir
)
3758 # Now update -r1 again. Hopefully we don't get a checksum error!
3759 expected_output
= svntest
.wc
.State(wc_dir
, {})
3760 # note: it's possible that the correct disk here should be the
3762 expected_disk
.tweak('iota', contents
=("This is the file 'iota'.\n"
3763 "Local mods to r1 text.\n"))
3764 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3765 expected_status
.tweak('iota', status
='M ')
3766 svntest
.actions
.run_and_verify_update(wc_dir
,
3777 #######################################################################
3781 # list all tests here, starting with None:
3784 update_binary_file_2
,
3785 update_ignores_added
,
3787 receive_overlapping_same_change
,
3788 update_to_resolve_text_conflicts
,
3789 update_delete_modified_files
,
3790 update_after_add_rm_deleted
,
3794 prop_update_on_scheduled_delete
,
3795 update_receive_illegal_name
,
3796 update_deleted_missing_dir
,
3797 another_hudson_problem
,
3798 update_deleted_targets
,
3799 new_dir_with_spaces
,
3800 non_recursive_update
,
3803 update_deletion_inside_out
,
3804 update_schedule_add_dir
,
3805 update_to_future_add
,
3806 nested_in_read_only
,
3807 obstructed_update_alters_wc_props
,
3808 update_xml_unsafe_dir
,
3809 conflict_markers_matching_eol
,
3810 update_eolstyle_handling
,
3811 update_copy_of_old_rev
,
3813 forced_update_failures
,
3814 XFail(update_wc_on_windows_drive
),
3815 update_wc_with_replaced_file
,
3816 update_with_obstructing_additions
,
3818 mergeinfo_update_elision
,
3819 SkipUnless(update_handles_copyfrom
,
3820 server_sends_copyfrom_on_update
),
3821 copyfrom_degrades_gracefully
,
3822 SkipUnless(update_handles_copyfrom_with_txdeltas
,
3823 server_sends_copyfrom_on_update
),
3824 update_copied_from_replaced_and_changed
,
3825 update_accept_conflicts
,
3826 eof_in_interactive_conflict_resolver
,
3829 if __name__
== '__main__':
3830 svntest
.main
.run_tests(test_list
)