Add a little more to the svn_rangelist_intersect test to test the
[svn.git] / subversion / tests / cmdline / update_tests.py
blobb0925a66f720cc3d22d049ce98cf2604d1508858
1 #!/usr/bin/env python
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 ######################################################################
19 # General modules
20 import sys, re, os
22 # Our testing module
23 import svntest
24 from svntest import wc
26 # (abbreviation)
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_MERGEINFO, server_sends_copyfrom_on_update
34 ######################################################################
35 # Tests
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:
56 wc_dir = fdata[0]
57 pattern = fdata[1]
58 contents = None
59 if len(fdata) > 2:
60 contents = fdata[2]
61 match_obj = re.match(pattern, node.name)
62 if match_obj:
63 if contents is None:
64 return
65 else:
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
69 return
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"
79 sbox.build()
80 wc_dir = sbox.wc_dir
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)
98 expected_status.add({
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, wc_dir)
106 # Make a backup copy of the working copy.
107 wc_backup = sbox.add_wc_path('backup')
108 svntest.actions.duplicate_dir(wc_dir, wc_backup)
109 theta_backup_path = os.path.join(wc_backup, 'A', 'theta')
111 # Make a change to the binary file in the original working copy
112 svntest.main.file_append(theta_path, "revision 3 text")
113 theta_contents_r3 = theta_contents + "revision 3 text"
115 # Created expected output tree for 'svn ci'
116 expected_output = svntest.wc.State(wc_dir, {
117 'A/theta' : Item(verb='Sending'),
120 # Create expected status tree
121 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
122 expected_status.add({
123 'A/theta' : Item(status=' ', wc_rev=3),
126 # Commit original working copy again, creating revision 3.
127 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
128 expected_status, None, wc_dir)
130 # Now start working in the backup working copy:
132 # Make a local mod to theta
133 svntest.main.file_append(theta_backup_path, "extra theta text")
134 theta_contents_local = theta_contents + "extra theta text"
136 # Create expected output tree for an update of wc_backup.
137 expected_output = svntest.wc.State(wc_backup, {
138 'A/theta' : Item(status='C '),
141 # Create expected disk tree for the update --
142 # look! binary contents, and a binary property!
143 expected_disk = svntest.main.greek_state.copy()
144 expected_disk.add({
145 'A/theta' : Item(theta_contents_local,
146 props={'svn:mime-type' : 'application/octet-stream'}),
149 # Create expected status tree for the update.
150 expected_status = svntest.actions.get_virginal_state(wc_backup, 3)
151 expected_status.add({
152 'A/theta' : Item(status='C ', wc_rev=3),
155 # Extra 'singleton' files we expect to exist after the update.
156 # In the case, the locally-modified binary file should be backed up
157 # to an .orig file.
158 # This is a list of lists, of the form [ WC_DIR,
159 # [pattern, contents], ...]
160 extra_files = [[wc_backup, 'theta.*\.r2', theta_contents],
161 [wc_backup, 'theta.*\.r3', theta_contents_r3]]
163 # Do the update and check the results in three ways. Pass our
164 # custom singleton handler to verify the .orig file; this handler
165 # will verify the existence (and contents) of both binary files
166 # after the update finishes.
167 svntest.actions.run_and_verify_update(wc_backup,
168 expected_output,
169 expected_disk,
170 expected_status,
171 None,
172 detect_extra_files, extra_files,
173 None, None, 1)
175 # verify that the extra_files list is now empty.
176 if len(extra_files) != 0:
177 print "Not all extra reject files have been accounted for:"
178 print extra_files
179 raise svntest.Failure
181 #----------------------------------------------------------------------
183 def update_binary_file_2(sbox):
184 "update to an old revision of a binary files"
186 sbox.build()
187 wc_dir = sbox.wc_dir
189 # Suck up contents of a test .png file.
190 theta_contents = svntest.main.file_read(
191 os.path.join(sys.path[0], "theta.bin"), 'rb')
193 # 102400 is svn_txdelta_window_size. We're going to make sure we
194 # have at least 102401 bytes of data in our second binary file (for
195 # no reason other than we have had problems in the past with getting
196 # svndiff data out of the repository for files > 102400 bytes).
197 # How? Well, we'll just keep doubling the binary contents of the
198 # original theta.png until we're big enough.
199 zeta_contents = theta_contents
200 while(len(zeta_contents) < 102401):
201 zeta_contents = zeta_contents + zeta_contents
203 # Write our two files' contents out to disk, in A/theta and A/zeta.
204 theta_path = os.path.join(wc_dir, 'A', 'theta')
205 svntest.main.file_write(theta_path, theta_contents, 'wb')
206 zeta_path = os.path.join(wc_dir, 'A', 'zeta')
207 svntest.main.file_write(zeta_path, zeta_contents, 'wb')
209 # Now, `svn add' those two files.
210 svntest.main.run_svn(None, 'add', theta_path, zeta_path)
212 # Created expected output tree for 'svn ci'
213 expected_output = svntest.wc.State(wc_dir, {
214 'A/theta' : Item(verb='Adding (bin)'),
215 'A/zeta' : Item(verb='Adding (bin)'),
218 # Create expected status tree
219 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
220 expected_status.add({
221 'A/theta' : Item(status=' ', wc_rev=2),
222 'A/zeta' : Item(status=' ', wc_rev=2),
225 # Commit the new binary filea, creating revision 2.
226 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
227 expected_status, None, wc_dir)
229 # Make some mods to the binary files.
230 svntest.main.file_append(theta_path, "foobar")
231 new_theta_contents = theta_contents + "foobar"
232 svntest.main.file_append(zeta_path, "foobar")
233 new_zeta_contents = zeta_contents + "foobar"
235 # Created expected output tree for 'svn ci'
236 expected_output = svntest.wc.State(wc_dir, {
237 'A/theta' : Item(verb='Sending'),
238 'A/zeta' : Item(verb='Sending'),
241 # Create expected status tree
242 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
243 expected_status.add({
244 'A/theta' : Item(status=' ', wc_rev=3),
245 'A/zeta' : Item(status=' ', wc_rev=3),
248 # Commit original working copy again, creating revision 3.
249 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
250 expected_status, None, wc_dir)
252 # Create expected output tree for an update to rev 2.
253 expected_output = svntest.wc.State(wc_dir, {
254 'A/theta' : Item(status='U '),
255 'A/zeta' : Item(status='U '),
258 # Create expected disk tree for the update --
259 # look! binary contents, and a binary property!
260 expected_disk = svntest.main.greek_state.copy()
261 expected_disk.add({
262 'A/theta' : Item(theta_contents,
263 props={'svn:mime-type' : 'application/octet-stream'}),
264 'A/zeta' : Item(zeta_contents,
265 props={'svn:mime-type' : 'application/octet-stream'}),
268 # Create expected status tree for the update.
269 expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
270 expected_status.add({
271 'A/theta' : Item(status=' ', wc_rev=2),
272 'A/zeta' : Item(status=' ', wc_rev=2),
275 # Do an update from revision 2 and make sure that our binary file
276 # gets reverted to its original contents.
277 svntest.actions.run_and_verify_update(wc_dir,
278 expected_output,
279 expected_disk,
280 expected_status,
281 None, None, None,
282 None, None, 1,
283 '-r', '2', wc_dir)
286 #----------------------------------------------------------------------
288 def update_missing(sbox):
289 "update missing items (by name) in working copy"
291 sbox.build()
292 wc_dir = sbox.wc_dir
294 # Remove some files and dirs from the working copy.
295 mu_path = os.path.join(wc_dir, 'A', 'mu')
296 rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
297 E_path = os.path.join(wc_dir, 'A', 'B', 'E')
298 H_path = os.path.join(wc_dir, 'A', 'D', 'H')
300 # remove two files to verify that they get restored
301 os.remove(mu_path)
302 os.remove(rho_path)
304 ### FIXME I think directories work because they generate 'A'
305 ### feedback, is this the correct feedback?
306 svntest.main.safe_rmtree(E_path)
307 svntest.main.safe_rmtree(H_path)
309 # Create expected output tree for an update of the missing items by name
310 expected_output = svntest.wc.State(wc_dir, {
311 'A/mu' : Item(verb='Restored'),
312 'A/D/G/rho' : Item(verb='Restored'),
313 'A/B/E' : Item(status='A '),
314 'A/B/E/alpha' : Item(status='A '),
315 'A/B/E/beta' : Item(status='A '),
316 'A/D/H' : Item(status='A '),
317 'A/D/H/chi' : Item(status='A '),
318 'A/D/H/omega' : Item(status='A '),
319 'A/D/H/psi' : Item(status='A '),
322 # Create expected disk tree for the update.
323 expected_disk = svntest.main.greek_state.copy()
325 # Create expected status tree for the update.
326 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
328 # Do the update and check the results in three ways.
329 svntest.actions.run_and_verify_update(wc_dir,
330 expected_output,
331 expected_disk,
332 expected_status,
333 None, None, None, None, None, 0,
334 mu_path, rho_path,
335 E_path, H_path)
337 #----------------------------------------------------------------------
339 def update_ignores_added(sbox):
340 "update should not munge adds or replaces"
342 sbox.build()
343 wc_dir = sbox.wc_dir
345 # Commit something so there's actually a new revision to update to.
346 rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
347 svntest.main.file_append(rho_path, "More stuff in rho.\n")
348 svntest.main.run_svn(None,
349 'ci', '-m', 'log msg', rho_path)
351 # Create a new file, 'zeta', and schedule it for addition.
352 zeta_path = os.path.join(wc_dir, 'A', 'B', 'zeta')
353 svntest.main.file_append(zeta_path, "This is the file 'zeta'.\n")
354 svntest.main.run_svn(None, 'add', zeta_path)
356 # Schedule another file, say, 'gamma', for replacement.
357 gamma_path = os.path.join(wc_dir, 'A', 'D', 'gamma')
358 svntest.main.run_svn(None, 'delete', gamma_path)
359 svntest.main.file_append(gamma_path, "This is a new 'gamma' now.\n")
360 svntest.main.run_svn(None, 'add', gamma_path)
362 # Now update. "zeta at revision 0" should *not* be reported at all,
363 # so it should remain scheduled for addition at revision 0. gamma
364 # was scheduled for replacement, so it also should remain marked as
365 # such, and maintain its revision of 1.
367 # Create expected output tree for an update of the wc_backup.
368 expected_output = svntest.wc.State(wc_dir, { })
370 # Create expected disk tree for the update.
371 expected_disk = svntest.main.greek_state.copy()
372 expected_disk.add({
373 'A/B/zeta' : Item("This is the file 'zeta'.\n"),
375 expected_disk.tweak('A/D/gamma', contents="This is a new 'gamma' now.\n")
376 expected_disk.tweak('A/D/G/rho',
377 contents="This is the file 'rho'.\nMore stuff in rho.\n")
379 # Create expected status tree for the update.
380 expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
381 expected_status.tweak('A/D/gamma', wc_rev=1, status='R ')
382 expected_status.add({
383 'A/B/zeta' : Item(status='A ', wc_rev=0),
386 # Do the update and check the results in three ways.
387 svntest.actions.run_and_verify_update(wc_dir,
388 expected_output,
389 expected_disk,
390 expected_status)
393 #----------------------------------------------------------------------
395 def update_to_rev_zero(sbox):
396 "update to revision 0"
398 sbox.build()
399 wc_dir = sbox.wc_dir
401 iota_path = os.path.join(wc_dir, 'iota')
402 A_path = os.path.join(wc_dir, 'A')
404 # Create expected output tree for an update to rev 0
405 expected_output = svntest.wc.State(wc_dir, {
406 'iota' : Item(status='D '),
407 'A' : Item(status='D '),
410 # Create expected disk tree for the update to rev 0
411 expected_disk = svntest.wc.State(wc_dir, { })
413 # Do the update and check the results.
414 svntest.actions.run_and_verify_update(wc_dir,
415 expected_output,
416 expected_disk,
417 None, None,
418 None, None, None, None, 0,
419 '-r', '0', wc_dir)
421 #----------------------------------------------------------------------
423 def receive_overlapping_same_change(sbox):
424 "overlapping identical changes should not conflict"
426 ### (See http://subversion.tigris.org/issues/show_bug.cgi?id=682.)
428 ### How this test works:
430 ### Create working copy foo, modify foo/iota. Duplicate foo,
431 ### complete with locally modified iota, to bar. Now we should
432 ### have:
434 ### $ svn st foo
435 ### M foo/iota
436 ### $ svn st bar
437 ### M bar/iota
438 ### $
440 ### Commit the change from foo, then update bar. The repository
441 ### change should get folded into bar/iota with no conflict, since
442 ### the two modifications are identical.
444 sbox.build()
445 wc_dir = sbox.wc_dir
447 # Modify iota.
448 iota_path = os.path.join(wc_dir, 'iota')
449 svntest.main.file_append(iota_path, "A change to iota.\n")
451 # Duplicate locally modified wc, giving us the "other" wc.
452 other_wc = sbox.add_wc_path('other')
453 svntest.actions.duplicate_dir(wc_dir, other_wc)
454 other_iota_path = os.path.join(other_wc, 'iota')
456 # Created expected output tree for 'svn ci'
457 expected_output = svntest.wc.State(wc_dir, {
458 'iota' : Item(verb='Sending'),
461 # Create expected status tree
462 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
463 expected_status.tweak('iota', wc_rev=2)
465 # Commit the change, creating revision 2.
466 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
467 expected_status, None, wc_dir)
469 # Expected output tree for update of other_wc.
470 expected_output = svntest.wc.State(other_wc, {
471 'iota' : Item(status='G '),
474 # Expected disk tree for the update.
475 expected_disk = svntest.main.greek_state.copy()
476 expected_disk.tweak('iota',
477 contents="This is the file 'iota'.\nA change to iota.\n")
479 # Expected status tree for the update.
480 expected_status = svntest.actions.get_virginal_state(other_wc, 2)
482 # Do the update and check the results in three ways.
483 svntest.actions.run_and_verify_update(other_wc,
484 expected_output,
485 expected_disk,
486 expected_status)
488 #----------------------------------------------------------------------
490 def update_to_resolve_text_conflicts(sbox):
491 "delete files and update to resolve text conflicts"
493 sbox.build()
494 wc_dir = sbox.wc_dir
496 # Make a backup copy of the working copy
497 wc_backup = sbox.add_wc_path('backup')
498 svntest.actions.duplicate_dir(wc_dir, wc_backup)
500 # Make a couple of local mods to files which will be committed
501 mu_path = os.path.join(wc_dir, 'A', 'mu')
502 rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
503 svntest.main.file_append(mu_path, 'Original appended text for mu\n')
504 svntest.main.file_append(rho_path, 'Original appended text for rho\n')
505 svntest.main.run_svn(None, 'propset', 'Kubla', 'Khan', rho_path)
507 # Make a couple of local mods to files which will be conflicted
508 mu_path_backup = os.path.join(wc_backup, 'A', 'mu')
509 rho_path_backup = os.path.join(wc_backup, 'A', 'D', 'G', 'rho')
510 svntest.main.file_append(mu_path_backup,
511 'Conflicting appended text for mu\n')
512 svntest.main.file_append(rho_path_backup,
513 'Conflicting appended text for rho\n')
514 svntest.main.run_svn(None, 'propset', 'Kubla', 'Xanadu', rho_path_backup)
516 # Created expected output tree for 'svn ci'
517 expected_output = svntest.wc.State(wc_dir, {
518 'A/mu' : Item(verb='Sending'),
519 'A/D/G/rho' : Item(verb='Sending'),
522 # Create expected status tree; all local revisions should be at 1,
523 # but mu and rho should be at revision 2.
524 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
525 expected_status.tweak('A/mu', wc_rev=2)
526 expected_status.tweak('A/D/G/rho', wc_rev=2, status=' ')
528 # Commit.
529 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
530 expected_status, None, wc_dir)
532 # Create expected output tree for an update of the wc_backup.
533 expected_output = svntest.wc.State(wc_backup, {
534 'A/mu' : Item(status='C '),
535 'A/D/G/rho' : Item(status='CC'),
538 # Create expected disk tree for the update.
539 expected_disk = svntest.main.greek_state.copy()
540 expected_disk.tweak('A/mu',
541 contents="\n".join(["This is the file 'mu'.",
542 "<<<<<<< .mine",
543 "Conflicting appended text for mu",
544 "=======",
545 "Original appended text for mu",
546 ">>>>>>> .r2",
547 ""]))
548 expected_disk.tweak('A/D/G/rho',
549 contents="\n".join(["This is the file 'rho'.",
550 "<<<<<<< .mine",
551 "Conflicting appended text for rho",
552 "=======",
553 "Original appended text for rho",
554 ">>>>>>> .r2",
555 ""]))
557 # Create expected status tree for the update.
558 expected_status = svntest.actions.get_virginal_state(wc_backup, 2)
559 expected_status.tweak('A/mu', status='C ')
560 expected_status.tweak('A/D/G/rho', status='CC')
562 # "Extra" files that we expect to result from the conflicts.
563 # These are expressed as list of regexps. What a cool system! :-)
564 extra_files = ['mu.*\.r1', 'mu.*\.r2', 'mu.*\.mine',
565 'rho.*\.r1', 'rho.*\.r2', 'rho.*\.mine', 'rho.*\.prej']
567 # Do the update and check the results in three ways.
568 # All "extra" files are passed to detect_conflict_files().
569 svntest.actions.run_and_verify_update(wc_backup,
570 expected_output,
571 expected_disk,
572 expected_status,
573 None,
574 svntest.tree.detect_conflict_files,
575 extra_files)
578 # verify that the extra_files list is now empty.
579 if len(extra_files) != 0:
580 print "didn't get expected extra files"
581 raise svntest.Failure
583 # remove the conflicting files to clear text conflict but not props conflict
584 os.remove(mu_path_backup)
585 os.remove(rho_path_backup)
587 # ### TODO: Can't get run_and_verify_update to work here :-( I get
588 # the error "Unequal Types: one Node is a file, the other is a
589 # directory". Use run_svn and then run_and_verify_status instead
590 stdout_lines, stdout_lines = svntest.main.run_svn(None, 'up', wc_backup)
591 if len (stdout_lines) > 0:
592 print "update 2 failed"
593 raise svntest.Failure
595 # Create expected status tree
596 expected_status = svntest.actions.get_virginal_state(wc_backup, 2)
597 expected_status.tweak('A/D/G/rho', status=' C')
599 svntest.actions.run_and_verify_status(wc_backup, expected_status)
601 #----------------------------------------------------------------------
603 def update_delete_modified_files(sbox):
604 "update that deletes modified files"
606 sbox.build()
607 wc_dir = sbox.wc_dir
609 # Delete a file
610 alpha_path = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
611 svntest.actions.run_and_verify_svn("Deleting alpha failed", None, [],
612 'rm', alpha_path)
614 # Delete a directory containing files
615 G_path = os.path.join(wc_dir, 'A', 'D', 'G')
616 svntest.actions.run_and_verify_svn("Deleting G failed", None, [],
617 'rm', G_path)
619 # Commit
620 svntest.actions.run_and_verify_svn("Committing deletes failed", None, [],
621 'ci', '-m', 'log msg', wc_dir)
623 # ### Update before backdating to avoid obstructed update error for G
624 svntest.actions.run_and_verify_svn("Updating after commit failed", None, [],
625 'up', wc_dir)
627 # Backdate to restore deleted items
628 svntest.actions.run_and_verify_svn("Backdating failed", None, [],
629 'up', '-r', '1', wc_dir)
631 # Modify the file to be deleted, and a file in the directory to be deleted
632 svntest.main.file_append(alpha_path, 'appended alpha text\n')
633 pi_path = os.path.join(G_path, 'pi')
634 svntest.main.file_append(pi_path, 'appended pi text\n')
636 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
637 expected_status.tweak('A/B/E/alpha', 'A/D/G/pi', status='M ')
639 svntest.actions.run_and_verify_status(wc_dir, expected_status)
641 # Now update to 'delete' modified files -- that is, remove them from
642 # version control, but leave them on disk. It used to be we would
643 # expect an 'obstructed update' error (see issue #1196), but
644 # nowadays we expect success (see issue #1806).
645 expected_output = svntest.wc.State(wc_dir, {
646 'A/B/E/alpha' : Item(status='D '),
647 'A/D/G' : Item(status='D '),
649 expected_disk = svntest.main.greek_state.copy()
650 expected_disk.tweak('A/B/E/alpha',
651 contents=\
652 "This is the file 'alpha'.\nappended alpha text\n")
653 expected_disk.tweak('A/D/G/pi',
654 contents=\
655 "This is the file 'pi'.\nappended pi text\n")
656 expected_disk.remove('A/D/G/rho')
657 expected_disk.remove('A/D/G/tau')
658 expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
659 expected_status.remove('A/B/E/alpha')
660 expected_status.remove('A/D/G')
661 expected_status.remove('A/D/G/pi')
662 expected_status.remove('A/D/G/rho')
663 expected_status.remove('A/D/G/tau')
664 svntest.actions.run_and_verify_update(wc_dir,
665 expected_output,
666 expected_disk,
667 expected_status)
670 #----------------------------------------------------------------------
672 # Issue 847. Doing an add followed by a remove for an item in state
673 # "deleted" caused the "deleted" state to get forgotten
675 def update_after_add_rm_deleted(sbox):
676 "update after add/rm of deleted state"
678 sbox.build()
679 wc_dir = sbox.wc_dir
681 # Delete a file and directory from WC
682 alpha_path = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
683 F_path = os.path.join(wc_dir, 'A', 'B', 'F')
684 svntest.actions.run_and_verify_svn(None, None, [], 'rm', alpha_path, F_path)
686 # Commit deletion
687 expected_output = svntest.wc.State(wc_dir, {
688 'A/B/E/alpha' : Item(verb='Deleting'),
689 'A/B/F' : Item(verb='Deleting'),
691 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
692 expected_status.remove('A/B/E/alpha')
693 expected_status.remove('A/B/F')
694 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
695 expected_status, None, wc_dir)
697 # alpha and F are now in state "deleted", next we add a new ones
698 svntest.main.file_append(alpha_path, "new alpha")
699 svntest.actions.run_and_verify_svn(None, None, [], 'add', alpha_path)
701 svntest.actions.run_and_verify_svn(None, None, [], 'mkdir', F_path)
703 # New alpha and F should be in add state A
704 expected_status.add({
705 'A/B/E/alpha' : Item(status='A ', wc_rev=0),
706 'A/B/F' : Item(status='A ', wc_rev=0),
708 svntest.actions.run_and_verify_status(wc_dir, expected_status)
710 # Forced removal of new alpha and F must restore "deleted" state
712 svntest.actions.run_and_verify_svn(None, None, [], 'rm', '--force',
713 alpha_path, F_path)
714 if os.path.exists(alpha_path) or os.path.exists(F_path):
715 raise svntest.Failure
717 # "deleted" state is not visible in status
718 expected_status.remove('A/B/E/alpha', 'A/B/F')
719 svntest.actions.run_and_verify_status(wc_dir, expected_status)
721 # Although parent dir is already at rev 1, the "deleted" state will cause
722 # alpha and F to be restored in the WC when updated to rev 1
723 svntest.actions.run_and_verify_svn(None, None, [], 'up', '-r', '1', wc_dir)
724 expected_status.add({
725 'A/B/E/alpha' : Item(status=' ', wc_rev=1),
726 'A/B/F' : Item(status=' ', wc_rev=1),
728 svntest.actions.run_and_verify_status(wc_dir, expected_status)
730 #----------------------------------------------------------------------
732 # Issue 1591. Updating a working copy which contains local
733 # obstructions marks a directory as incomplete. Removal of the
734 # obstruction and subsequent update should clear the "incomplete"
735 # flag.
737 def obstructed_update_alters_wc_props(sbox):
738 "obstructed update alters WC properties"
740 sbox.build()
741 wc_dir = sbox.wc_dir
743 # Create a new dir in the repo in prep for creating an obstruction.
744 #print "Adding dir to repo"
745 svntest.actions.run_and_verify_svn(None, None, [],
746 'mkdir', '-m',
747 'prep for obstruction',
748 sbox.repo_url + '/A/foo')
750 # Create an obstruction, a file in the WC with the same name as
751 # present in a newer rev of the repo.
752 #print "Creating obstruction"
753 obstruction_parent_path = os.path.join(wc_dir, 'A')
754 obstruction_path = os.path.join(obstruction_parent_path, 'foo')
755 svntest.main.file_append(obstruction_path, 'an obstruction')
757 # Update the WC to that newer rev to trigger the obstruction.
758 #print "Updating WC"
759 expected_output = svntest.wc.State(wc_dir, {})
760 expected_disk = svntest.main.greek_state.copy()
761 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
762 error_re = 'Failed to add directory.*object of the same name already exists'
763 svntest.actions.run_and_verify_update(wc_dir,
764 expected_output,
765 expected_disk,
766 expected_status,
767 error_re)
769 # Remove the file which caused the obstruction.
770 #print "Removing obstruction"
771 os.unlink(obstruction_path)
773 # Update the -- now unobstructed -- WC again.
774 #print "Updating WC again"
775 expected_output = svntest.wc.State(wc_dir, {
776 'A/foo' : Item(status='A '),
778 expected_disk = svntest.main.greek_state.copy()
779 expected_disk.add({
780 'A/foo' : Item(),
782 expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
783 expected_status.add({
784 'A/foo' : Item(status=' ', wc_rev=2),
786 svntest.actions.run_and_verify_update(wc_dir,
787 expected_output,
788 expected_disk,
789 expected_status)
791 # The previously obstructed resource should now be in the WC.
792 if not os.path.isdir(obstruction_path):
793 raise svntest.Failure
795 #----------------------------------------------------------------------
797 # Issue 938.
798 def update_replace_dir(sbox):
799 "update that replaces a directory"
801 sbox.build()
802 wc_dir = sbox.wc_dir
804 # Delete a directory
805 F_path = os.path.join(wc_dir, 'A', 'B', 'F')
806 svntest.actions.run_and_verify_svn(None, None, [], 'rm', F_path)
808 # Commit deletion
809 expected_output = svntest.wc.State(wc_dir, {
810 'A/B/F' : Item(verb='Deleting'),
812 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
813 expected_status.remove('A/B/F')
814 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
815 expected_status, None, wc_dir)
817 # Add replacement directory
818 svntest.actions.run_and_verify_svn(None, None, [], 'mkdir', F_path)
820 # Commit addition
821 expected_output = svntest.wc.State(wc_dir, {
822 'A/B/F' : Item(verb='Adding'),
824 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
825 expected_status.tweak('A/B/F', wc_rev=3)
826 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
827 expected_status, None, wc_dir)
829 # Update to HEAD
830 expected_output = svntest.wc.State(wc_dir, {
832 expected_disk = svntest.main.greek_state.copy()
833 expected_status = svntest.actions.get_virginal_state(wc_dir, 3)
834 svntest.actions.run_and_verify_update(wc_dir,
835 expected_output,
836 expected_disk,
837 expected_status)
839 # Update to revision 1 replaces the directory
840 ### I can't get this to work :-(
841 #expected_output = svntest.wc.State(wc_dir, {
842 # 'A/B/F' : Item(verb='Adding'),
843 # 'A/B/F' : Item(verb='Deleting'),
844 # })
845 #expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
846 #svntest.actions.run_and_verify_update(wc_dir,
847 # expected_output,
848 # expected_disk,
849 # expected_status,
850 # None, None, None, None, None, 0,
851 # '-r', '1', wc_dir)
853 # Update to revision 1 replaces the directory
854 svntest.actions.run_and_verify_svn(None, None, [], 'up', '-r', '1', wc_dir)
855 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
856 svntest.actions.run_and_verify_status(wc_dir, expected_status)
858 #----------------------------------------------------------------------
860 def update_single_file(sbox):
861 "update with explicit file target"
863 sbox.build()
864 wc_dir = sbox.wc_dir
866 expected_disk = svntest.main.greek_state.copy()
868 # Make a local mod to a file which will be committed
869 mu_path = os.path.join(wc_dir, 'A', 'mu')
870 svntest.main.file_append(mu_path, '\nAppended text for mu')
872 # Commit.
873 expected_output = svntest.wc.State(wc_dir, {
874 'A/mu' : Item(verb='Sending'),
876 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
877 expected_status.tweak('A/mu', wc_rev=2)
878 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
879 expected_status, None, wc_dir)
881 # At one stage 'svn up file' failed with a parent lock error
882 was_cwd = os.getcwd()
883 os.chdir(os.path.join(wc_dir, 'A'))
885 ### Can't get run_and_verify_update to work having done the chdir.
886 svntest.actions.run_and_verify_svn("update failed", None, [],
887 'up', '-r', '1', 'mu')
888 os.chdir(was_cwd)
890 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
891 svntest.actions.run_and_verify_status(wc_dir, expected_status)
893 #----------------------------------------------------------------------
894 def prop_update_on_scheduled_delete(sbox):
895 "receive prop update to file scheduled for deletion"
897 sbox.build()
898 wc_dir = sbox.wc_dir
900 other_wc = sbox.add_wc_path('other')
902 # Make the "other" working copy.
903 svntest.actions.duplicate_dir(wc_dir, other_wc)
905 iota_path = os.path.join(wc_dir, 'iota')
906 other_iota_path = os.path.join(other_wc, 'iota')
908 svntest.main.run_svn(None, 'propset', 'foo', 'bar', iota_path)
910 # Created expected output tree for 'svn ci'
911 expected_output = svntest.wc.State(wc_dir, {
912 'iota' : Item(verb='Sending'),
915 # Create expected status tree
916 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
917 expected_status.tweak('iota', wc_rev=2)
919 # Commit the change, creating revision 2.
920 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
921 expected_status, None, wc_dir)
923 svntest.main.run_svn(None, 'rm', other_iota_path)
925 # Expected output tree for update of other_wc.
926 expected_output = svntest.wc.State(other_wc, {
927 'iota' : Item(status=' U'),
930 # Expected disk tree for the update.
931 expected_disk = svntest.main.greek_state.copy()
932 expected_disk.remove('iota')
934 # Expected status tree for the update.
935 expected_status = svntest.actions.get_virginal_state(other_wc, 2)
936 expected_status.tweak('iota', status='D ')
938 # Do the update and check the results in three ways.
939 svntest.actions.run_and_verify_update(other_wc,
940 expected_output,
941 expected_disk,
942 expected_status)
944 #----------------------------------------------------------------------
946 def update_receive_illegal_name(sbox):
947 "bail when receive a file or dir named .svn"
949 sbox.build()
950 wc_dir = sbox.wc_dir
952 # This tests the revision 4334 fix for issue #1068.
954 legal_url = sbox.repo_url + '/A/D/G/svn'
955 illegal_url = (sbox.repo_url
956 + '/A/D/G/' + svntest.main.get_admin_name())
957 # Ha! The client doesn't allow us to mkdir a '.svn' but it does
958 # allow us to copy to a '.svn' so ...
959 svntest.actions.run_and_verify_svn(None, None, [],
960 'mkdir', '-m', 'log msg',
961 legal_url)
962 svntest.actions.run_and_verify_svn(None, None, [],
963 'mv', '-m', 'log msg',
964 legal_url, illegal_url)
966 # Do the update twice, both should fail. After the first failure
967 # the wc will be marked "incomplete".
968 for n in range(2):
969 out, err = svntest.main.run_svn(1, 'up', wc_dir)
970 for line in err:
971 if line.find("an unversioned directory of the same " \
972 "name already exists") != -1:
973 break
974 else:
975 raise svntest.Failure
977 # At one stage an obstructed update in an incomplete wc would leave
978 # a txn behind
979 out, err = svntest.main.run_svnadmin('lstxns', sbox.repo_dir)
980 if out or err:
981 raise svntest.Failure
983 #----------------------------------------------------------------------
985 def update_deleted_missing_dir(sbox):
986 "update missing dir to rev in which it is absent"
988 sbox.build()
989 wc_dir = sbox.wc_dir
991 E_path = os.path.join(wc_dir, 'A', 'B', 'E')
992 H_path = os.path.join(wc_dir, 'A', 'D', 'H')
994 # Create a new revision with directories deleted
995 svntest.main.run_svn(None, 'rm', E_path)
996 svntest.main.run_svn(None, 'rm', H_path)
997 svntest.main.run_svn(None,
998 'ci', '-m', 'log msg', E_path, H_path)
1000 # Update back to the old revision
1001 svntest.main.run_svn(None,
1002 'up', '-r', '1', wc_dir)
1004 # Delete the directories from disk
1005 svntest.main.safe_rmtree(E_path)
1006 svntest.main.safe_rmtree(H_path)
1008 # Create expected output tree for an update of the missing items by name
1009 expected_output = svntest.wc.State(wc_dir, {
1010 'A/B/E' : Item(status='D '),
1011 'A/D/H' : Item(status='D '),
1014 # Create expected disk tree for the update.
1015 expected_disk = svntest.main.greek_state.copy()
1016 expected_disk.remove('A/B/E', 'A/B/E/alpha', 'A/B/E/beta')
1017 expected_disk.remove('A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi')
1019 # Create expected status tree for the update.
1020 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
1021 expected_status.remove('A/B/E', 'A/B/E/alpha', 'A/B/E/beta')
1022 expected_status.remove('A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi')
1024 # Do the update, specifying the deleted paths explicitly.
1025 svntest.actions.run_and_verify_update(wc_dir,
1026 expected_output,
1027 expected_disk,
1028 expected_status,
1029 None, None, None, None, None,
1030 0, "-r", "2", E_path, H_path)
1032 # Update back to the old revision again
1033 svntest.main.run_svn(None,
1034 'up', '-r', '1', wc_dir)
1036 # Delete the directories from disk
1037 svntest.main.safe_rmtree(E_path)
1038 svntest.main.safe_rmtree(H_path)
1040 # This time we're updating the whole working copy
1041 expected_status.tweak(wc_rev=2)
1043 # Do the update, on the whole working copy this time
1044 svntest.actions.run_and_verify_update(wc_dir,
1045 expected_output,
1046 expected_disk,
1047 expected_status,
1048 None, None, None, None, None,
1049 0, "-r", "2", wc_dir)
1051 #----------------------------------------------------------------------
1053 # Issue 919. This test was written as a regression test for "item
1054 # should remain 'deleted' when an update deletes a sibling".
1055 def another_hudson_problem(sbox):
1056 "another \"hudson\" problem: updates that delete"
1058 sbox.build()
1059 wc_dir = sbox.wc_dir
1061 # Delete/commit gamma thus making it 'deleted'
1062 gamma_path = os.path.join(wc_dir, 'A', 'D', 'gamma')
1063 svntest.main.run_svn(None, 'rm', gamma_path)
1064 expected_output = svntest.wc.State(wc_dir, {
1065 'A/D/gamma' : Item(verb='Deleting'),
1067 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
1068 expected_status.remove('A/D/gamma')
1069 svntest.actions.run_and_verify_commit(wc_dir,
1070 expected_output,
1071 expected_status,
1072 None, wc_dir)
1074 # Delete directory G from the repository
1075 svntest.actions.run_and_verify_svn(None,
1076 ['\n', 'Committed revision 3.\n'], [],
1077 'rm', '-m', 'log msg',
1078 sbox.repo_url + '/A/D/G')
1080 # Remove corresponding tree from working copy
1081 G_path = os.path.join(wc_dir, 'A', 'D', 'G')
1082 svntest.main.safe_rmtree(G_path)
1084 # Update missing directory to receive the delete, this should mark G
1085 # as 'deleted' and should not alter gamma's entry.
1087 # Sigh, I can't get run_and_verify_update to work (but not because
1088 # of issue 919 as far as I can tell)
1089 svntest.actions.run_and_verify_svn(None,
1090 ['D '+G_path+'\n',
1091 'Updated to revision 3.\n'], [],
1092 'up', G_path)
1094 # Both G and gamma should be 'deleted', update should produce no output
1095 expected_output = svntest.wc.State(wc_dir, { })
1096 expected_status = svntest.actions.get_virginal_state(wc_dir, 3)
1097 expected_status.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau',
1098 'A/D/gamma')
1099 expected_disk = svntest.main.greek_state.copy()
1100 expected_disk.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau',
1101 'A/D/gamma')
1102 svntest.actions.run_and_verify_update(wc_dir,
1103 expected_output,
1104 expected_disk,
1105 expected_status)
1107 #----------------------------------------------------------------------
1108 def update_deleted_targets(sbox):
1109 "explicit update of deleted=true targets"
1111 sbox.build()
1112 wc_dir = sbox.wc_dir
1114 # Delete/commit thus creating 'deleted=true' entries
1115 gamma_path = os.path.join(wc_dir, 'A', 'D', 'gamma')
1116 F_path = os.path.join(wc_dir, 'A', 'B', 'F')
1117 svntest.main.run_svn(None, 'rm', gamma_path, F_path)
1118 expected_output = svntest.wc.State(wc_dir, {
1119 'A/D/gamma' : Item(verb='Deleting'),
1120 'A/B/F' : Item(verb='Deleting'),
1122 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
1123 expected_status.remove('A/D/gamma', 'A/B/F')
1124 svntest.actions.run_and_verify_commit(wc_dir,
1125 expected_output,
1126 expected_status,
1127 None, wc_dir)
1129 # Explicit update must not remove the 'deleted=true' entries
1130 svntest.actions.run_and_verify_svn(None, ['At revision 2.\n'], [],
1131 'update', gamma_path)
1132 svntest.actions.run_and_verify_svn(None, ['At revision 2.\n'], [],
1133 'update', F_path)
1135 # Update to r1 to restore items, since the parent directory is already
1136 # at r1 this fails if the 'deleted=true' entries are missing (issue 2250)
1137 expected_output = svntest.wc.State(wc_dir, {
1138 'A/D/gamma' : Item(status='A '),
1139 'A/B/F' : Item(status='A '),
1141 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
1142 expected_disk = svntest.main.greek_state.copy()
1143 svntest.actions.run_and_verify_update(wc_dir,
1144 expected_output,
1145 expected_disk,
1146 expected_status,
1147 None, None, None, None, None, 0,
1148 '-r', '1', wc_dir)
1152 #----------------------------------------------------------------------
1154 def new_dir_with_spaces(sbox):
1155 "receive new dir with spaces in its name"
1157 sbox.build()
1158 wc_dir = sbox.wc_dir
1160 # Create a new directory ("spacey dir") directly in repository
1161 svntest.actions.run_and_verify_svn(None,
1162 ['\n', 'Committed revision 2.\n'], [],
1163 'mkdir', '-m', 'log msg',
1164 sbox.repo_url
1165 + '/A/spacey%20dir')
1167 # Update, and make sure ra_neon doesn't choke on the space.
1168 expected_output = svntest.wc.State(wc_dir, {
1169 'A/spacey dir' : Item(status='A '),
1171 expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
1172 expected_status.add({
1173 'A/spacey dir' : Item(status=' ', wc_rev=2),
1175 expected_disk = svntest.main.greek_state.copy()
1176 expected_disk.add({
1177 'A/spacey dir' : Item(),
1180 svntest.actions.run_and_verify_update(wc_dir,
1181 expected_output,
1182 expected_disk,
1183 expected_status)
1185 #----------------------------------------------------------------------
1187 def non_recursive_update(sbox):
1188 "non-recursive update"
1190 sbox.build()
1191 wc_dir = sbox.wc_dir
1193 # Commit a change to A/mu and A/D/G/rho
1194 mu_path = os.path.join(wc_dir, 'A', 'mu')
1195 rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
1196 svntest.main.file_append(mu_path, "new")
1197 svntest.main.file_append(rho_path, "new")
1198 expected_output = svntest.wc.State(wc_dir, {
1199 'A/mu' : Item(verb='Sending'),
1200 'A/D/G/rho' : Item(verb='Sending'),
1202 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
1203 expected_status.tweak('A/mu', 'A/D/G/rho', wc_rev=2)
1204 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
1205 expected_status,
1206 None, wc_dir)
1208 # Update back to revision 1
1209 expected_output = svntest.wc.State(wc_dir, {
1210 'A/mu' : Item(status='U '),
1211 'A/D/G/rho' : Item(status='U '),
1213 expected_disk = svntest.main.greek_state.copy()
1214 expected_status.tweak('A/mu', 'A/D/G/rho', wc_rev=1)
1215 svntest.actions.run_and_verify_update(wc_dir, expected_output,
1216 expected_disk, expected_status,
1217 None, None, None, None, None, 0,
1218 '-r', '1', wc_dir)
1220 # Non-recursive update of A should change A/mu but not A/D/G/rho
1221 A_path = os.path.join(wc_dir, 'A')
1222 expected_output = svntest.wc.State(wc_dir, {
1223 'A/mu' : Item(status='U '),
1225 expected_status.tweak('A', 'A/mu', wc_rev=2)
1226 expected_disk.tweak('A/mu', contents="This is the file 'mu'.\nnew")
1227 svntest.actions.run_and_verify_update(wc_dir, expected_output,
1228 expected_disk, expected_status,
1229 None, None, None, None, None, 0,
1230 '-N', A_path)
1232 #----------------------------------------------------------------------
1234 def checkout_empty_dir(sbox):
1235 "check out an empty dir"
1236 # See issue #1472 -- checked out empty dir should not be marked as
1237 # incomplete ("!" in status).
1238 sbox.build(create_wc = False)
1239 wc_dir = sbox.wc_dir
1241 C_url = sbox.repo_url + '/A/C'
1243 svntest.main.safe_rmtree(wc_dir)
1244 svntest.actions.run_and_verify_svn(None, None, [], 'checkout', C_url, wc_dir)
1246 svntest.actions.run_and_verify_svn(None, [], [], 'status', wc_dir)
1249 #----------------------------------------------------------------------
1250 # Regression test for issue #919: "another ghudson bug". Basically, if
1251 # we fore- or back-date an item until it no longer exists, we were
1252 # completely removing the entry, rather than marking it 'deleted'
1253 # (which we now do.)
1255 def update_to_deletion(sbox):
1256 "update target till it's gone, then get it back"
1258 sbox.build()
1259 wc_dir = sbox.wc_dir
1261 iota_path = os.path.join(wc_dir, 'iota')
1263 # Update iota to rev 0, so it gets removed.
1264 expected_output = svntest.wc.State(wc_dir, {
1265 'iota' : Item(status='D '),
1267 expected_disk = svntest.main.greek_state.copy()
1268 expected_disk.remove('iota')
1270 svntest.actions.run_and_verify_update(wc_dir,
1271 expected_output,
1272 expected_disk,
1273 None, None,
1274 None, None, None, None, 0,
1275 '-r', '0', iota_path)
1277 # Update the wc root, so iota comes back.
1278 expected_output = svntest.wc.State(wc_dir, {
1279 'iota' : Item(status='A '),
1281 expected_disk = svntest.main.greek_state.copy()
1283 svntest.actions.run_and_verify_update(wc_dir,
1284 expected_output,
1285 expected_disk,
1286 None, None,
1287 None, None, None, None, 0,
1288 wc_dir)
1291 #----------------------------------------------------------------------
1293 def update_deletion_inside_out(sbox):
1294 "update child before parent of a deleted tree"
1296 sbox.build()
1297 wc_dir = sbox.wc_dir
1299 parent_path = os.path.join(wc_dir, 'A', 'B')
1300 child_path = os.path.join(parent_path, 'E') # Could be a file, doesn't matter
1302 # Delete the parent directory.
1303 svntest.actions.run_and_verify_svn(None, None, [],
1304 'rm', parent_path)
1305 svntest.actions.run_and_verify_svn(None, None, [],
1306 'ci', '-m', '', wc_dir)
1308 # Update back to r1.
1309 svntest.actions.run_and_verify_svn(None, None, [],
1310 'update', '-r', '1', wc_dir)
1312 # Update just the child to r2.
1313 svntest.actions.run_and_verify_svn(None, None, [],
1314 'update', '-r', '2', child_path)
1316 # Now try a normal update.
1317 expected_output = svntest.wc.State(wc_dir, {
1318 'A/B' : Item(status='D '),
1320 expected_disk = svntest.main.greek_state.copy()
1321 expected_disk.remove('A/B', 'A/B/lambda', 'A/B/F',
1322 'A/B/E', 'A/B/E/alpha', 'A/B/E/beta')
1324 svntest.actions.run_and_verify_update(wc_dir,
1325 expected_output,
1326 expected_disk,
1327 None)
1330 #----------------------------------------------------------------------
1331 # Regression test for issue #1793, whereby 'svn up dir' would delete
1332 # dir if schedule-add. Yikes.
1334 def update_schedule_add_dir(sbox):
1335 "update a schedule-add directory"
1337 sbox.build()
1338 wc_dir = sbox.wc_dir
1340 # Delete directory A/D/G in the repository via immediate commit
1341 G_path = os.path.join(wc_dir, 'A', 'D', 'G')
1342 G_url = sbox.repo_url + '/A/D/G'
1343 svntest.actions.run_and_verify_svn(None, None, [],
1344 'rm', G_url, '-m', 'rev 2')
1346 # Update the wc to HEAD (r2)
1347 expected_output = svntest.wc.State(wc_dir, {
1348 'A/D/G' : Item(status='D '),
1350 expected_disk = svntest.main.greek_state.copy()
1351 expected_disk.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
1352 expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
1353 expected_status.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
1354 svntest.actions.run_and_verify_update(wc_dir,
1355 expected_output,
1356 expected_disk,
1357 expected_status)
1359 # Do a URL->wc copy, creating a new schedule-add A/D/G.
1360 # (Standard procedure when trying to resurrect the directory.)
1361 D_path = os.path.join(wc_dir, 'A', 'D')
1362 svntest.actions.run_and_verify_svn("Copy error:", None, [],
1363 'cp', G_url + '@1', D_path)
1365 # status should now show the dir scheduled for addition-with-history
1366 expected_status.add({
1367 'A/D/G' : Item(status='A ', copied='+', wc_rev='-'),
1368 'A/D/G/pi' : Item(status=' ', copied='+', wc_rev='-'),
1369 'A/D/G/rho' : Item(status=' ', copied='+', wc_rev='-'),
1370 'A/D/G/tau' : Item(status=' ', copied='+', wc_rev='-'),
1372 svntest.actions.run_and_verify_status(wc_dir, expected_status)
1374 # Now update with the schedule-add dir as the target.
1375 svntest.actions.run_and_verify_svn(None, None, [], 'up', G_path)
1377 # The update should be a no-op, and the schedule-add directory
1378 # should still exist! 'svn status' shouldn't change at all.
1379 svntest.actions.run_and_verify_status(wc_dir, expected_status)
1382 #----------------------------------------------------------------------
1383 # Test updating items that do not exist in the current WC rev, but do
1384 # exist at some future revision.
1386 def update_to_future_add(sbox):
1387 "update target that was added in a future rev"
1389 sbox.build()
1390 wc_dir = sbox.wc_dir
1392 # Update the entire WC to rev 0
1393 # Create expected output tree for an update to rev 0
1394 expected_output = svntest.wc.State(wc_dir, {
1395 'iota' : Item(status='D '),
1396 'A' : Item(status='D '),
1399 # Create expected disk tree for the update to rev 0
1400 expected_disk = svntest.wc.State(wc_dir, { })
1402 # Do the update and check the results.
1403 svntest.actions.run_and_verify_update(wc_dir,
1404 expected_output,
1405 expected_disk,
1406 None, None,
1407 None, None, None, None, 0,
1408 '-r', '0', wc_dir)
1410 # Update iota to the current HEAD.
1411 iota_path = os.path.join(wc_dir, 'iota')
1412 expected_output = svntest.wc.State(wc_dir, {
1413 'iota' : Item(status='A '),
1415 expected_disk = svntest.wc.State('', {
1416 'iota' : Item("This is the file 'iota'.\n")
1419 svntest.actions.run_and_verify_update(wc_dir,
1420 expected_output,
1421 expected_disk,
1422 None, None,
1423 None, None, None, None, 0,
1424 iota_path)
1426 # Now try updating the directory into the future
1427 A_path = os.path.join(wc_dir, 'A')
1429 expected_output = svntest.wc.State(wc_dir, {
1430 'A' : Item(status='A '),
1431 'A/mu' : Item(status='A '),
1432 'A/B' : Item(status='A '),
1433 'A/B/lambda' : Item(status='A '),
1434 'A/B/E' : Item(status='A '),
1435 'A/B/E/alpha' : Item(status='A '),
1436 'A/B/E/beta' : Item(status='A '),
1437 'A/B/F' : Item(status='A '),
1438 'A/C' : Item(status='A '),
1439 'A/D' : Item(status='A '),
1440 'A/D/gamma' : Item(status='A '),
1441 'A/D/G' : Item(status='A '),
1442 'A/D/G/pi' : Item(status='A '),
1443 'A/D/G/rho' : Item(status='A '),
1444 'A/D/G/tau' : Item(status='A '),
1445 'A/D/H' : Item(status='A '),
1446 'A/D/H/chi' : Item(status='A '),
1447 'A/D/H/psi' : Item(status='A '),
1448 'A/D/H/omega' : Item(status='A ')
1450 expected_disk = svntest.main.greek_state.copy()
1452 svntest.actions.run_and_verify_update(wc_dir,
1453 expected_output,
1454 expected_disk,
1455 None, None,
1456 None, None, None, None, 0,
1457 A_path);
1459 #----------------------------------------------------------------------
1461 def nested_in_read_only(sbox):
1462 "update a nested wc in a read-only wc"
1464 sbox.build()
1465 wc_dir = sbox.wc_dir
1467 # Delete/commit a file
1468 alpha_path = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
1469 svntest.actions.run_and_verify_svn(None, None, [], 'rm', alpha_path)
1470 expected_output = svntest.wc.State(wc_dir, {
1471 'A/B/E/alpha' : Item(verb='Deleting'),
1473 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
1474 expected_status.remove('A/B/E/alpha')
1475 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
1476 expected_status, None, wc_dir)
1477 svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
1478 expected_status.tweak(wc_rev=2)
1479 svntest.actions.run_and_verify_status(wc_dir, expected_status)
1481 # Delete/commit a directory that used to contain the deleted file
1482 B_path = os.path.join(wc_dir, 'A', 'B')
1483 svntest.actions.run_and_verify_svn(None, None, [], 'rm', B_path)
1484 expected_output = svntest.wc.State(wc_dir, {
1485 'A/B' : Item(verb='Deleting'),
1487 expected_status.remove('A/B', 'A/B/lambda', 'A/B/E', 'A/B/E/beta', 'A/B/F')
1488 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
1489 expected_status, None, wc_dir)
1491 svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
1492 expected_status.tweak(wc_rev=3)
1493 svntest.actions.run_and_verify_status(wc_dir, expected_status)
1495 # Replace the deleted directory with a new checkout of an old
1496 # version of the directory, this gives it a "plausible" URL that
1497 # could be part of the containing wc
1498 B_url = sbox.repo_url + '/A/B'
1499 svntest.actions.run_and_verify_svn(None, None, [],
1500 'checkout', '-r', '1', B_url + "@1",
1501 B_path)
1502 expected_status = svntest.wc.State(B_path, {
1503 '' : Item(),
1504 'lambda' : Item(),
1505 'E' : Item(),
1506 'E/alpha' : Item(),
1507 'E/beta' : Item(),
1508 'F' : Item(),
1510 expected_status.tweak(wc_rev=1, status=' ')
1511 svntest.actions.run_and_verify_status(B_path, expected_status)
1513 # Make enclosing wc read only
1514 os.chmod(os.path.join(wc_dir, 'A', svntest.main.get_admin_name()), 0555)
1516 try:
1517 # Update of nested wc should still work
1518 expected_output = svntest.wc.State(B_path, {
1519 'E/alpha' : Item(status='D '),
1521 expected_disk = wc.State('', {
1522 'lambda' : wc.StateItem("This is the file 'lambda'.\n"),
1523 'E' : wc.StateItem(),
1524 'E/beta' : wc.StateItem("This is the file 'beta'.\n"),
1525 'F' : wc.StateItem(),
1527 expected_status.remove('E/alpha')
1528 expected_status.tweak(wc_rev=2)
1529 svntest.actions.run_and_verify_update(B_path,
1530 expected_output,
1531 expected_disk,
1532 expected_status,
1533 None, None, None, None, None, 0,
1534 '-r', '2', B_path)
1535 finally:
1536 os.chmod(os.path.join(wc_dir, 'A', svntest.main.get_admin_name()), 0777)
1538 #----------------------------------------------------------------------
1540 def update_xml_unsafe_dir(sbox):
1541 "update dir with xml-unsafe name"
1543 sbox.build()
1544 wc_dir = sbox.wc_dir
1546 # Make a backup copy of the working copy
1547 wc_backup = sbox.add_wc_path('backup')
1548 svntest.actions.duplicate_dir(wc_dir, wc_backup)
1550 # Make a couple of local mods to files
1551 test_path = os.path.join(wc_dir, ' foo & bar')
1552 svntest.main.run_svn(None, 'mkdir', test_path)
1554 # Created expected output tree for 'svn ci'
1555 expected_output = wc.State(wc_dir, {
1556 ' foo & bar' : Item(verb='Adding'),
1559 # Create expected status tree; all local revisions should be at 1,
1560 # but 'foo & bar' should be at revision 2.
1561 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
1562 expected_status.add({
1563 ' foo & bar' : Item(status=' ', wc_rev=2),
1566 # Commit.
1567 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
1568 expected_status, None, wc_dir)
1570 # chdir into the funky path, and update from there.
1571 os.chdir(test_path)
1573 expected_output = wc.State('', {
1575 expected_disk = wc.State('', {
1577 expected_status = wc.State('', {
1578 '' : Item(status=' ', wc_rev=2),
1580 svntest.actions.run_and_verify_update('', expected_output, expected_disk,
1581 expected_status)
1583 #----------------------------------------------------------------------
1584 # eol-style handling during update with conflicts, scenario 1:
1585 # when update creates a conflict on a file, make sure the file and files
1586 # r<left>, r<right> and .mine are in the eol-style defined for that file.
1588 # This test for 'svn merge' can be found in merge_tests.py as
1589 # merge_conflict_markers_matching_eol.
1590 def conflict_markers_matching_eol(sbox):
1591 "conflict markers should match the file's eol style"
1593 sbox.build()
1594 wc_dir = sbox.wc_dir
1595 filecount = 1
1597 mu_path = os.path.join(wc_dir, 'A', 'mu')
1599 if os.name == 'nt':
1600 crlf = '\n'
1601 else:
1602 crlf = '\r\n'
1604 # Checkout a second working copy
1605 wc_backup = sbox.add_wc_path('backup')
1606 svntest.actions.run_and_verify_svn(None, None, [], 'checkout',
1607 sbox.repo_url, wc_backup)
1609 # set starting revision
1610 cur_rev = 1
1612 expected_disk = svntest.main.greek_state.copy()
1613 expected_status = svntest.actions.get_virginal_state(wc_dir, cur_rev)
1614 expected_backup_status = svntest.actions.get_virginal_state(wc_backup,
1615 cur_rev)
1617 path_backup = os.path.join(wc_backup, 'A', 'mu')
1619 # do the test for each eol-style
1620 for eol, eolchar in zip(['CRLF', 'CR', 'native', 'LF'],
1621 [crlf, '\015', '\n', '\012']):
1622 # rewrite file mu and set the eol-style property.
1623 svntest.main.file_write(mu_path, "This is the file 'mu'."+ eolchar, 'wb')
1624 svntest.main.run_svn(None, 'propset', 'svn:eol-style', eol, mu_path)
1626 expected_disk.add({
1627 'A/mu' : Item("This is the file 'mu'." + eolchar)
1629 expected_output = svntest.wc.State(wc_dir, {
1630 'A/mu' : Item(verb='Sending'),
1632 expected_status.tweak(wc_rev = cur_rev)
1633 expected_status.add({
1634 'A/mu' : Item(status=' ', wc_rev = cur_rev + 1),
1637 # Commit the original change and note the 'base' revision number
1638 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
1639 expected_status, None, wc_dir)
1640 cur_rev = cur_rev + 1
1641 base_rev = cur_rev
1643 svntest.main.run_svn(None, 'update', wc_backup)
1645 # Make a local mod to mu
1646 svntest.main.file_append(mu_path,
1647 'Original appended text for mu' + eolchar)
1649 # Commit the original change and note the 'theirs' revision number
1650 svntest.main.run_svn(None, 'commit', '-m', 'test log', wc_dir)
1651 cur_rev = cur_rev + 1
1652 theirs_rev = cur_rev
1654 # Make a local mod to mu, will conflict with the previous change
1655 svntest.main.file_append(path_backup,
1656 'Conflicting appended text for mu' + eolchar)
1658 # Create expected output tree for an update of the wc_backup.
1659 expected_backup_output = svntest.wc.State(wc_backup, {
1660 'A/mu' : Item(status='C '),
1663 # Create expected disk tree for the update.
1664 expected_backup_disk = expected_disk.copy()
1666 # verify content of resulting conflicted file
1667 expected_backup_disk.add({
1668 'A/mu' : Item(contents= "This is the file 'mu'." + eolchar +
1669 "<<<<<<< .mine" + eolchar +
1670 "Conflicting appended text for mu" + eolchar +
1671 "=======" + eolchar +
1672 "Original appended text for mu" + eolchar +
1673 ">>>>>>> .r" + str(cur_rev) + eolchar),
1675 # verify content of base(left) file
1676 expected_backup_disk.add({
1677 'A/mu.r' + str(base_rev ) : Item(contents= "This is the file 'mu'." +
1678 eolchar)
1680 # verify content of theirs(right) file
1681 expected_backup_disk.add({
1682 'A/mu.r' + str(theirs_rev ) : Item(contents= "This is the file 'mu'." +
1683 eolchar +
1684 "Original appended text for mu" + eolchar)
1686 # verify content of mine file
1687 expected_backup_disk.add({
1688 'A/mu.mine' : Item(contents= "This is the file 'mu'." +
1689 eolchar +
1690 "Conflicting appended text for mu" + eolchar)
1693 # Create expected status tree for the update.
1694 expected_backup_status.add({
1695 'A/mu' : Item(status=' ', wc_rev=cur_rev),
1697 expected_backup_status.tweak('A/mu', status='C ')
1698 expected_backup_status.tweak(wc_rev = cur_rev)
1700 # Do the update and check the results in three ways.
1701 svntest.actions.run_and_verify_update(wc_backup,
1702 expected_backup_output,
1703 expected_backup_disk,
1704 expected_backup_status,
1705 None,
1706 None,
1707 None)
1709 # cleanup for next run
1710 svntest.main.run_svn(None, 'revert', '-R', wc_backup)
1711 svntest.main.run_svn(None, 'update', wc_dir)
1713 # eol-style handling during update, scenario 2:
1714 # if part of that update is a propchange (add, change, delete) of
1715 # svn:eol-style, make sure the correct eol-style is applied before
1716 # calculating the merge (and conflicts if any)
1718 # This test for 'svn merge' can be found in merge_tests.py as
1719 # merge_eolstyle_handling.
1720 def update_eolstyle_handling(sbox):
1721 "handle eol-style propchange during update"
1723 sbox.build()
1724 wc_dir = sbox.wc_dir
1726 mu_path = os.path.join(wc_dir, 'A', 'mu')
1728 if os.name == 'nt':
1729 crlf = '\n'
1730 else:
1731 crlf = '\r\n'
1733 # Checkout a second working copy
1734 wc_backup = sbox.add_wc_path('backup')
1735 svntest.actions.run_and_verify_svn(None, None, [], 'checkout',
1736 sbox.repo_url, wc_backup)
1737 path_backup = os.path.join(wc_backup, 'A', 'mu')
1739 # Test 1: add the eol-style property and commit, change mu in the second
1740 # working copy and update; there should be no conflict!
1741 svntest.main.run_svn(None, 'propset', 'svn:eol-style', "CRLF", mu_path)
1742 svntest.main.run_svn(None,
1743 'commit', '-m', 'set eol-style property', wc_dir)
1745 svntest.main.file_append_binary(path_backup, 'Added new line of text.\012')
1747 expected_backup_disk = svntest.main.greek_state.copy()
1748 expected_backup_disk.tweak(
1749 'A/mu', contents= "This is the file 'mu'." + crlf +
1750 "Added new line of text." + crlf)
1751 expected_backup_output = svntest.wc.State(wc_backup, {
1752 'A/mu' : Item(status='GU'),
1754 expected_backup_status = svntest.actions.get_virginal_state(wc_backup, 2)
1755 expected_backup_status.tweak('A/mu', status='M ')
1757 svntest.actions.run_and_verify_update(wc_backup,
1758 expected_backup_output,
1759 expected_backup_disk,
1760 expected_backup_status,
1761 None, None, None)
1763 # Test 2: now change the eol-style property to another value and commit,
1764 # update the still changed mu in the second working copy; there should be
1765 # no conflict!
1766 svntest.main.run_svn(None, 'propset', 'svn:eol-style', "CR", mu_path)
1767 svntest.main.run_svn(None,
1768 'commit', '-m', 'set eol-style property', wc_dir)
1770 expected_backup_disk = svntest.main.greek_state.copy()
1771 expected_backup_disk.add({
1772 'A/mu' : Item(contents= "This is the file 'mu'.\015" +
1773 "Added new line of text.\015")
1775 expected_backup_output = svntest.wc.State(wc_backup, {
1776 'A/mu' : Item(status='GU'),
1778 expected_backup_status = svntest.actions.get_virginal_state(wc_backup, 3)
1779 expected_backup_status.tweak('A/mu', status='M ')
1780 svntest.actions.run_and_verify_update(wc_backup,
1781 expected_backup_output,
1782 expected_backup_disk,
1783 expected_backup_status,
1784 None, None, None)
1786 # Test 3: now delete the eol-style property and commit, update the still
1787 # changed mu in the second working copy; there should be no conflict!
1788 # EOL of mu should be unchanged (=CR).
1789 svntest.main.run_svn(None, 'propdel', 'svn:eol-style', mu_path)
1790 svntest.main.run_svn(None,
1791 'commit', '-m', 'del eol-style property', wc_dir)
1793 expected_backup_disk = svntest.main.greek_state.copy()
1794 expected_backup_disk.add({
1795 'A/mu' : Item(contents= "This is the file 'mu'.\015" +
1796 "Added new line of text.\015")
1798 expected_backup_output = svntest.wc.State(wc_backup, {
1799 'A/mu' : Item(status=' U'),
1801 expected_backup_status = svntest.actions.get_virginal_state(wc_backup, 4)
1802 expected_backup_status.tweak('A/mu', status='M ')
1803 svntest.actions.run_and_verify_update(wc_backup,
1804 expected_backup_output,
1805 expected_backup_disk,
1806 expected_backup_status,
1807 None, None, None)
1809 # Bug in which "update" put a bogus revision number on a schedule-add file,
1810 # causing the wrong version of it to be committed.
1811 def update_copy_of_old_rev(sbox):
1812 "update schedule-add copy of old rev"
1814 sbox.build()
1815 wc_dir = sbox.wc_dir
1817 dir = os.path.join(wc_dir, 'A')
1818 dir2 = os.path.join(wc_dir, 'A2')
1819 file = os.path.join(dir, 'mu')
1820 file2 = os.path.join(dir2, 'mu')
1821 url = sbox.repo_url + '/A/mu'
1822 url2 = sbox.repo_url + '/A2/mu'
1824 # Remember the original text of the file
1825 text_r1, err = svntest.actions.run_and_verify_svn(None, None, [],
1826 'cat', '-r1', url)
1828 # Commit a different version of the file
1829 svntest.main.file_write(file, "Second revision of 'mu'\n")
1830 svntest.actions.run_and_verify_svn(None, None, [],
1831 'ci', '-m', '', wc_dir)
1833 # Copy an old revision of its directory into a new path in the WC
1834 svntest.actions.run_and_verify_svn(None, None, [],
1835 'cp', '-r1', dir, dir2)
1837 # Update. (Should do nothing, but added a bogus "revision" in "entries".)
1838 svntest.actions.run_and_verify_svn(None, None, [],
1839 'up', wc_dir)
1841 # Commit, and check that it says it's committing the right thing
1842 exp_out = ['Adding ' + dir2 + '\n',
1843 '\n',
1844 'Committed revision 3.\n']
1845 svntest.actions.run_and_verify_svn(None, exp_out, [],
1846 'ci', '-m', '', wc_dir)
1848 # Verify the committed file's content
1849 svntest.actions.run_and_verify_svn(None, text_r1, [],
1850 'cat', url2)
1852 #----------------------------------------------------------------------
1853 def forced_update(sbox):
1854 "forced update tolerates obstructions to adds"
1856 sbox.build()
1857 wc_dir = sbox.wc_dir
1859 # Make a backup copy of the working copy
1860 wc_backup = sbox.add_wc_path('backup')
1861 svntest.actions.duplicate_dir(wc_dir, wc_backup)
1863 # Make a couple of local mods to files
1864 mu_path = os.path.join(wc_dir, 'A', 'mu')
1865 rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
1866 svntest.main.file_append(mu_path, 'appended mu text')
1867 svntest.main.file_append(rho_path, 'new appended text for rho')
1869 # Add some files
1870 nu_path = os.path.join(wc_dir, 'A', 'B', 'F', 'nu')
1871 svntest.main.file_append(nu_path, "This is the file 'nu'\n")
1872 svntest.main.run_svn(None, 'add', nu_path)
1873 kappa_path = os.path.join(wc_dir, 'kappa')
1874 svntest.main.file_append(kappa_path, "This is the file 'kappa'\n")
1875 svntest.main.run_svn(None, 'add', kappa_path)
1877 # Add a dir with two files
1878 I_path = os.path.join(wc_dir, 'A', 'C', 'I')
1879 os.mkdir(I_path)
1880 svntest.main.run_svn(None, 'add', I_path)
1881 upsilon_path = os.path.join(I_path, 'upsilon')
1882 svntest.main.file_append(upsilon_path, "This is the file 'upsilon'\n")
1883 svntest.main.run_svn(None, 'add', upsilon_path)
1884 zeta_path = os.path.join(I_path, 'zeta')
1885 svntest.main.file_append(zeta_path, "This is the file 'zeta'\n")
1886 svntest.main.run_svn(None, 'add', zeta_path)
1888 # Created expected output tree for 'svn ci'
1889 expected_output = wc.State(wc_dir, {
1890 'A/mu' : Item(verb='Sending'),
1891 'A/D/G/rho' : Item(verb='Sending'),
1892 'A/B/F/nu' : Item(verb='Adding'),
1893 'kappa' : Item(verb='Adding'),
1894 'A/C/I' : Item(verb='Adding'),
1895 'A/C/I/upsilon' : Item(verb='Adding'),
1896 'A/C/I/zeta' : Item(verb='Adding'),
1899 # Create expected status tree.
1900 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
1901 expected_status.add({
1902 'A/B/F/nu' : Item(status=' ', wc_rev=2),
1903 'kappa' : Item(status=' ', wc_rev=2),
1904 'A/C/I' : Item(status=' ', wc_rev=2),
1905 'A/C/I/upsilon' : Item(status=' ', wc_rev=2),
1906 'A/C/I/zeta' : Item(status=' ', wc_rev=2),
1908 expected_status.tweak('A/mu', 'A/D/G/rho', wc_rev=2)
1910 # Commit.
1911 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
1912 expected_status, None, wc_dir)
1914 # Make a local mod to mu that will merge cleanly.
1915 backup_mu_path = os.path.join(wc_backup, 'A', 'mu')
1916 svntest.main.file_append(backup_mu_path, 'appended mu text')
1918 # Create unversioned files and dir that will obstruct A/B/F/nu, kappa,
1919 # A/C/I, and A/C/I/upsilon coming from repos during update.
1920 # The obstructing nu has the same contents as the repos, while kappa and
1921 # upsilon differ, which means the latter two should show as modified after
1922 # the forced update.
1923 nu_path = os.path.join(wc_backup, 'A', 'B', 'F', 'nu')
1924 svntest.main.file_append(nu_path, "This is the file 'nu'\n")
1925 kappa_path = os.path.join(wc_backup, 'kappa')
1926 svntest.main.file_append(kappa_path,
1927 "This is the OBSTRUCTING file 'kappa'\n")
1928 I_path = os.path.join(wc_backup, 'A', 'C', 'I')
1929 os.mkdir(I_path)
1930 upsilon_path = os.path.join(I_path, 'upsilon')
1931 svntest.main.file_append(upsilon_path,
1932 "This is the OBSTRUCTING file 'upsilon'\n")
1934 # Create expected output tree for an update of the wc_backup.
1935 # mu and rho are run of the mill update operations; merge and update
1936 # respectively.
1937 # kappa, nu, I, and upsilon all 'E'xisted as unversioned items in the WC.
1938 # While the dir I does exist, zeta does not so it's just an add.
1939 expected_output = wc.State(wc_backup, {
1940 'A/mu' : Item(status='G '),
1941 'A/D/G/rho' : Item(status='U '),
1942 'kappa' : Item(status='E '),
1943 'A/B/F/nu' : Item(status='E '),
1944 'A/C/I' : Item(status='E '),
1945 'A/C/I/upsilon' : Item(status='E '),
1946 'A/C/I/zeta' : Item(status='A '),
1949 # Create expected output tree for an update of the wc_backup.
1951 # - mu and rho are run of the mill update operations; merge and update
1952 # respectively.
1954 # - kappa, nu, I, and upsilon all 'E'xisted as unversioned items in the WC.
1956 # - While the dir I does exist, I/zeta does not so it's just an add.
1957 expected_disk = svntest.main.greek_state.copy()
1958 expected_disk.add({
1959 'A/B/F/nu' : Item("This is the file 'nu'\n"),
1960 'kappa' : Item("This is the OBSTRUCTING file 'kappa'\n"),
1961 'A/C/I' : Item(),
1962 'A/C/I/upsilon' : Item("This is the OBSTRUCTING file 'upsilon'\n"),
1963 'A/C/I/zeta' : Item("This is the file 'zeta'\n"),
1965 expected_disk.tweak('A/mu',
1966 contents=expected_disk.desc['A/mu'].contents
1967 + 'appended mu text')
1968 expected_disk.tweak('A/D/G/rho',
1969 contents=expected_disk.desc['A/D/G/rho'].contents
1970 + 'new appended text for rho')
1972 # Create expected status tree for the update. Since the obstructing
1973 # kappa and upsilon differ from the repos, they should show as modified.
1974 expected_status = svntest.actions.get_virginal_state(wc_backup, 2)
1975 expected_status.add({
1976 'A/B/F/nu' : Item(status=' ', wc_rev=2),
1977 'A/C/I' : Item(status=' ', wc_rev=2),
1978 'A/C/I/zeta' : Item(status=' ', wc_rev=2),
1979 'kappa' : Item(status='M ', wc_rev=2),
1980 'A/C/I/upsilon' : Item(status='M ', wc_rev=2),
1983 # Perform forced update and check the results in three ways.
1984 svntest.actions.run_and_verify_update(wc_backup,
1985 expected_output,
1986 expected_disk,
1987 expected_status,
1988 None, None, None, None, None, 0,
1989 wc_backup, '--force')
1991 #----------------------------------------------------------------------
1992 def forced_update_failures(sbox):
1993 "forced up fails with some types of obstructions"
1995 sbox.build()
1996 wc_dir = sbox.wc_dir
1998 # Make a backup copy of the working copy
1999 wc_backup = sbox.add_wc_path('backup')
2000 svntest.actions.duplicate_dir(wc_dir, wc_backup)
2002 # Add a file
2003 nu_path = os.path.join(wc_dir, 'A', 'B', 'F', 'nu')
2004 svntest.main.file_append(nu_path, "This is the file 'nu'\n")
2005 svntest.main.run_svn(None, 'add', nu_path)
2007 # Add a dir
2008 I_path = os.path.join(wc_dir, 'A', 'C', 'I')
2009 os.mkdir(I_path)
2010 svntest.main.run_svn(None, 'add', I_path)
2012 # Created expected output tree for 'svn ci'
2013 expected_output = wc.State(wc_dir, {
2014 'A/B/F/nu' : Item(verb='Adding'),
2015 'A/C/I' : Item(verb='Adding'),
2018 # Create expected status tree.
2019 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
2020 expected_status.add({
2021 'A/B/F/nu' : Item(status=' ', wc_rev=2),
2022 'A/C/I' : Item(status=' ', wc_rev=2),
2025 # Commit.
2026 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2027 expected_status, None, wc_dir)
2029 # Create an unversioned dir A/B/F/nu that will obstruct the file of the
2030 # same name coming from the repository. Create an unversioned file A/C/I
2031 # that will obstruct the dir of the same name.
2032 nu_path = os.path.join(wc_backup, 'A', 'B', 'F', 'nu')
2033 os.mkdir(nu_path)
2034 I_path = os.path.join(wc_backup, 'A', 'C', 'I')
2035 svntest.main.file_append(I_path,
2036 "This is the file 'I'...shouldn't I be a dir?\n")
2038 # A forced update that tries to add a file when an unversioned directory
2039 # of the same name already exists should fail.
2040 F_Path = os.path.join(wc_backup, 'A', 'B', 'F')
2041 svntest.actions.run_and_verify_update(F_Path, None, None, None,
2042 ".*Failed to add file.*" + \
2043 "a non-file object of the " + \
2044 "same name already exists",
2045 None, None, None, None, 0, F_Path,
2046 '--force')
2048 # A forced update that tries to add a directory when an unversioned file
2049 # of the same name already exists should fail.
2050 C_Path = os.path.join(wc_backup, 'A', 'C')
2051 svntest.actions.run_and_verify_update(C_Path, None, None, None,
2052 ".*Failed to add directory.*" + \
2053 "a non-directory object of the " + \
2054 "same name already exists",
2055 None, None, None, None, 0, C_Path,
2056 '--force')
2058 # A forced update that tries to add a directory when a versioned directory
2059 # of the same name already exists should fail.
2061 # Remove the file A/C/I and make it a versioned directory.
2062 I_url = sbox.repo_url + "/A/C/I"
2063 os.remove(I_path)
2064 os.mkdir(I_path)
2065 so, se = svntest.actions.run_and_verify_svn("Unexpected error during co",
2066 ['Checked out revision 2.\n'],
2067 [], "co", I_url, I_path)
2069 svntest.actions.run_and_verify_update(C_Path, None, None, None,
2070 ".*Failed to add " + \
2071 "directory.*a versioned directory " + \
2072 "of the same name already exists",
2073 None, None, None, None, 0, C_Path,
2074 '--force')
2076 #----------------------------------------------------------------------
2077 # Test for issue #2556. The tests maps a virtual drive to a working copy
2078 # and tries some basic update, commit and status actions on the virtual
2079 # drive.
2080 def update_wc_on_windows_drive(sbox):
2081 "update wc on the root of a Windows (virtual) drive"
2083 def find_the_next_available_drive_letter():
2084 "find the first available drive"
2086 # get the list of used drive letters, use some Windows specific function.
2087 try:
2088 import win32api
2090 drives=win32api.GetLogicalDriveStrings()
2091 drives=drives.split('\000')
2093 for d in range(ord('G'), ord('Z')+1):
2094 drive = chr(d)
2095 if not drive + ':\\' in drives:
2096 return drive
2097 except ImportError:
2098 return None
2100 return None
2102 # just create an empty folder, we'll checkout later.
2103 sbox.build(create_wc = False)
2104 svntest.main.safe_rmtree(sbox.wc_dir)
2105 os.mkdir(sbox.wc_dir)
2107 # create a virtual drive to the working copy folder
2108 drive = find_the_next_available_drive_letter()
2109 if drive is None:
2110 raise svntest.Skip
2112 os.popen3('subst ' + drive +': ' + sbox.wc_dir, 't')
2113 wc_dir = drive + ':/'
2114 was_cwd = os.getcwd()
2116 try:
2117 svntest.actions.run_and_verify_svn(None, None, [],
2118 'checkout',
2119 sbox.repo_url, wc_dir)
2121 # Make some local modifications
2122 mu_path = os.path.join(wc_dir, 'A', 'mu')
2123 svntest.main.file_append(mu_path, '\nAppended text for mu')
2124 zeta_path = os.path.join(wc_dir, 'zeta')
2125 svntest.main.file_append(zeta_path, "This is the file 'zeta'\n")
2126 svntest.main.run_svn(None, 'add', zeta_path)
2128 # Commit.
2129 expected_output = svntest.wc.State(wc_dir, {
2130 'A/mu' : Item(verb='Sending'),
2131 'zeta' : Item(verb='Adding'),
2133 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
2134 expected_status.tweak('A/mu', wc_rev=2)
2135 expected_status.add({
2136 'zeta' : Item(status=' ', wc_rev=2),
2138 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2139 expected_status, None,
2140 wc_dir, zeta_path)
2142 # Non recursive commit
2143 dir1_path = os.path.join(wc_dir, 'dir1')
2144 os.mkdir(dir1_path)
2145 svntest.main.run_svn(None, 'add', '-N', dir1_path)
2146 file1_path = os.path.join(dir1_path, 'file1')
2147 svntest.main.file_append(file1_path, "This is the file 'file1'\n")
2148 svntest.main.run_svn(None, 'add', '-N', file1_path)
2150 expected_output = svntest.wc.State(wc_dir, {
2151 'dir1' : Item(verb='Adding'),
2152 'dir1/file1' : Item(verb='Adding'),
2154 expected_status.add({
2155 'dir1' : Item(status=' ', wc_rev=3),
2156 'dir1/file1' : Item(status=' ', wc_rev=3),
2158 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2159 expected_status, None,
2160 '-N',
2161 wc_dir,
2162 dir1_path, file1_path)
2164 # revert to previous revision to test update
2165 os.chdir(wc_dir)
2167 expected_disk = svntest.main.greek_state.copy()
2168 expected_output = svntest.wc.State(wc_dir, {
2169 'A/mu' : Item(status='U '),
2170 'zeta' : Item(status='D '),
2171 'dir1' : Item(status='D '),
2173 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
2174 svntest.actions.run_and_verify_update(wc_dir,
2175 expected_output,
2176 expected_disk,
2177 expected_status,
2178 None, None, None, None, None, 0,
2179 '-r', '1', wc_dir)
2181 os.chdir(was_cwd)
2183 # update to the latest version, but use the relative path 'X:'
2184 wc_dir = drive + ":"
2185 expected_output = svntest.wc.State(wc_dir, {
2186 'A/mu' : Item(status='U '),
2187 'zeta' : Item(status='A '),
2188 'dir1' : Item(status='A '),
2189 'dir1/file1' : Item(status='A '),
2191 expected_status = svntest.actions.get_virginal_state(wc_dir, 3)
2192 expected_status.add({
2193 'dir1' : Item(status=' ', wc_rev=3),
2194 'dir1/file1' : Item(status=' ', wc_rev=3),
2195 'zeta' : Item(status=' ', wc_rev=3),
2197 expected_disk.add({
2198 'zeta' : Item("This is the file 'zeta'\n"),
2199 'dir1/file1': Item("This is the file 'file1'\n"),
2201 expected_disk.tweak('A/mu', contents = expected_disk.desc['A/mu'].contents
2202 + '\nAppended text for mu')
2203 svntest.actions.run_and_verify_update(wc_dir,
2204 expected_output,
2205 expected_disk,
2206 expected_status)
2208 finally:
2209 os.chdir(was_cwd)
2210 # cleanup the virtual drive
2211 os.popen3('subst /D ' + drive +': ', 't')
2213 # Issue #2618: update a working copy with a replaced file.
2214 def update_wc_with_replaced_file(sbox):
2215 "update wc containing a replaced-with-history file"
2217 sbox.build()
2218 wc_dir = sbox.wc_dir
2220 # Make a backup copy of the working copy.
2221 wc_backup = sbox.add_wc_path('backup')
2222 svntest.actions.duplicate_dir(wc_dir, wc_backup)
2224 # we need a change in the repository
2225 iota_path = os.path.join(wc_dir, 'iota')
2226 mu_path = os.path.join(wc_dir, 'A', 'mu')
2227 iota_bu_path = os.path.join(wc_backup, 'iota')
2228 svntest.main.file_append(iota_bu_path, "New line in 'iota'\n")
2229 svntest.main.run_svn(None,
2230 'ci', wc_backup, '-m', 'changed file')
2232 # First, a replacement without history.
2233 svntest.main.run_svn(None, 'rm', iota_path)
2234 svntest.main.file_append(iota_path, "")
2235 svntest.main.run_svn(None, 'add', iota_path)
2237 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
2238 expected_status.tweak('iota', status='R ', wc_rev='1')
2239 svntest.actions.run_and_verify_status(wc_dir, expected_status)
2241 # Now update the wc
2242 expected_output = svntest.wc.State(wc_dir, {
2243 'iota' : Item(status='C '),
2245 expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
2246 expected_status.add({
2247 'iota' : Item(status='C ', wc_rev='2'),
2249 expected_disk = svntest.main.greek_state.copy()
2250 expected_disk.tweak('iota',
2251 contents="\n".join(["<<<<<<< .mine",
2252 "=======",
2253 "This is the file 'iota'.",
2254 "New line in 'iota'",
2255 ">>>>>>> .r2",
2256 ""]))
2257 conflict_files = [ 'iota.*\.r1', 'iota.*\.r2', 'iota.*\.mine' ]
2258 svntest.actions.run_and_verify_update(wc_dir,
2259 expected_output,
2260 expected_disk,
2261 expected_status,
2262 None,
2263 svntest.tree.detect_conflict_files,
2264 conflict_files)
2266 # Make us a working copy with a 'replace-with-history' file.
2267 svntest.main.run_svn(None, 'revert', iota_path)
2268 expected_output = svntest.wc.State(wc_dir, {
2269 'iota' : Item(status='U '),
2271 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
2272 expected_disk = svntest.main.greek_state.copy()
2273 svntest.actions.run_and_verify_update(wc_dir,
2274 expected_output,
2275 expected_disk,
2276 expected_status,
2277 None,
2278 None, None, None, None, 0,
2279 wc_dir, '-r1')
2281 svntest.main.run_svn(None, 'rm', iota_path)
2282 svntest.main.run_svn(None, 'cp', mu_path, iota_path)
2284 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
2285 expected_status.tweak('iota', status='R ', copied='+', wc_rev='-')
2286 svntest.actions.run_and_verify_status(wc_dir, expected_status)
2288 # Now update the wc
2289 expected_output = svntest.wc.State(wc_dir, {
2290 'iota' : Item(status='C '),
2292 expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
2293 expected_status.add({
2294 'iota' : Item(status='CM', wc_rev='-', copied='+'),
2296 expected_disk = svntest.main.greek_state.copy()
2297 expected_disk.tweak('iota',
2298 contents="\n".join(["<<<<<<< .mine",
2299 "This is the file 'mu'.",
2300 "=======",
2301 "This is the file 'iota'.",
2302 "New line in 'iota'",
2303 ">>>>>>> .r2",
2304 ""]))
2305 conflict_files = [ 'iota.*\.r1', 'iota.*\.r2', 'iota.*\.mine' ]
2306 svntest.actions.run_and_verify_update(wc_dir,
2307 expected_output,
2308 expected_disk,
2309 expected_status,
2310 None,
2311 svntest.tree.detect_conflict_files,
2312 conflict_files)
2314 #----------------------------------------------------------------------
2315 def update_with_obstructing_additions(sbox):
2316 "update handles obstructing paths scheduled for add"
2318 sbox.build()
2319 wc_dir = sbox.wc_dir
2321 # Make a backup copy of the working copy
2322 wc_backup = sbox.add_wc_path('backup')
2323 svntest.actions.duplicate_dir(wc_dir, wc_backup)
2325 # Add files and dirs to the repos via the first WC. Each of these
2326 # will be added to the backup WC via an update:
2328 # A/B/upsilon: Identical to the file scheduled for addition in
2329 # the backup WC.
2331 # A/C/nu: A "normal" add, won't exist in the backup WC.
2333 # A/D/kappa: Textual and property conflict with the file scheduled
2334 # for addition in the backup WC.
2336 # A/D/epsilon: Textual conflict with the file scheduled for addition.
2338 # A/D/zeta: Prop conflict with the file scheduled for addition.
2340 # Three new dirs that will also be scheduled for addition:
2341 # A/D/H/I: No props on either WC or REPOS.
2342 # A/D/H/I/J: Prop conflict with the scheduled add.
2343 # A/D/H/I/K: Same (mergeable) prop on WC and REPOS.
2345 # A/D/H/I/K/xi: Identical to the file scheduled for addition in
2346 # the backup WC. No props.
2348 # A/D/H/I/L: A "normal" dir add, won't exist in the backup WC.
2350 # A/D/H/I/J/eta: Conflicts with the file scheduled for addition in
2351 # the backup WC. No props.
2352 upsilon_path = os.path.join(wc_dir, 'A', 'B', 'upsilon')
2353 svntest.main.file_append(upsilon_path, "This is the file 'upsilon'\n")
2354 nu_path = os.path.join(wc_dir, 'A', 'C', 'nu')
2355 svntest.main.file_append(nu_path, "This is the file 'nu'\n")
2356 kappa_path = os.path.join(wc_dir, 'A', 'D', 'kappa')
2357 svntest.main.file_append(kappa_path, "This is REPOS file 'kappa'\n")
2358 epsilon_path = os.path.join(wc_dir, 'A', 'D', 'epsilon')
2359 svntest.main.file_append(epsilon_path, "This is REPOS file 'epsilon'\n")
2360 zeta_path = os.path.join(wc_dir, 'A', 'D', 'zeta')
2361 svntest.main.file_append(zeta_path, "This is the file 'zeta'\n")
2362 I_path = os.path.join(wc_dir, 'A', 'D', 'H', 'I')
2363 os.mkdir(I_path)
2364 J_path = os.path.join(I_path, 'J')
2365 os.mkdir(J_path)
2366 K_path = os.path.join(I_path, 'K')
2367 os.mkdir(K_path)
2368 L_path = os.path.join(I_path, 'L')
2369 os.mkdir(L_path)
2370 xi_path = os.path.join(K_path, 'xi')
2371 svntest.main.file_append(xi_path, "This is the file 'xi'\n")
2372 eta_path = os.path.join(J_path, 'eta')
2373 svntest.main.file_append(eta_path, "This is REPOS file 'eta'\n")
2374 svntest.main.run_svn(None, 'add', upsilon_path, nu_path,
2375 kappa_path, epsilon_path, zeta_path, I_path)
2377 # Set props that will conflict with scheduled adds.
2378 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-REPOS',
2379 kappa_path)
2380 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-REPOS',
2381 zeta_path)
2382 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-REPOS',
2383 J_path)
2385 # Set prop that will match with scheduled add.
2386 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-SAME',
2387 epsilon_path)
2388 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-SAME',
2389 K_path)
2391 # Created expected output tree for 'svn ci'
2392 expected_output = wc.State(wc_dir, {
2393 'A/B/upsilon' : Item(verb='Adding'),
2394 'A/C/nu' : Item(verb='Adding'),
2395 'A/D/kappa' : Item(verb='Adding'),
2396 'A/D/epsilon' : Item(verb='Adding'),
2397 'A/D/zeta' : Item(verb='Adding'),
2398 'A/D/H/I' : Item(verb='Adding'),
2399 'A/D/H/I/J' : Item(verb='Adding'),
2400 'A/D/H/I/J/eta' : Item(verb='Adding'),
2401 'A/D/H/I/K' : Item(verb='Adding'),
2402 'A/D/H/I/K/xi' : Item(verb='Adding'),
2403 'A/D/H/I/L' : Item(verb='Adding'),
2406 # Create expected status tree.
2407 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
2408 expected_status.add({
2409 'A/B/upsilon' : Item(status=' ', wc_rev=2),
2410 'A/C/nu' : Item(status=' ', wc_rev=2),
2411 'A/D/kappa' : Item(status=' ', wc_rev=2),
2412 'A/D/epsilon' : Item(status=' ', wc_rev=2),
2413 'A/D/zeta' : Item(status=' ', wc_rev=2),
2414 'A/D/H/I' : Item(status=' ', wc_rev=2),
2415 'A/D/H/I/J' : Item(status=' ', wc_rev=2),
2416 'A/D/H/I/J/eta' : Item(status=' ', wc_rev=2),
2417 'A/D/H/I/K' : Item(status=' ', wc_rev=2),
2418 'A/D/H/I/K/xi' : Item(status=' ', wc_rev=2),
2419 'A/D/H/I/L' : Item(status=' ', wc_rev=2),
2422 # Commit.
2423 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2424 expected_status, None, wc_dir)
2426 # Create various paths scheduled for addition which will obstruct
2427 # the adds coming from the repos.
2428 upsilon_backup_path = os.path.join(wc_backup, 'A', 'B', 'upsilon')
2429 svntest.main.file_append(upsilon_backup_path,
2430 "This is the file 'upsilon'\n")
2431 kappa_backup_path = os.path.join(wc_backup, 'A', 'D', 'kappa')
2432 svntest.main.file_append(kappa_backup_path,
2433 "This is WC file 'kappa'\n")
2434 epsilon_backup_path = os.path.join(wc_backup, 'A', 'D', 'epsilon')
2435 svntest.main.file_append(epsilon_backup_path,
2436 "This is WC file 'epsilon'\n")
2437 zeta_backup_path = os.path.join(wc_backup, 'A', 'D', 'zeta')
2438 svntest.main.file_append(zeta_backup_path, "This is the file 'zeta'\n")
2439 I_backup_path = os.path.join(wc_backup, 'A', 'D', 'H', 'I')
2440 os.mkdir(I_backup_path)
2441 J_backup_path = os.path.join(I_backup_path, 'J')
2442 os.mkdir(J_backup_path)
2443 K_backup_path = os.path.join(I_backup_path, 'K')
2444 os.mkdir(K_backup_path)
2445 xi_backup_path = os.path.join(K_backup_path, 'xi')
2446 svntest.main.file_append(xi_backup_path, "This is the file 'xi'\n")
2447 eta_backup_path = os.path.join(J_backup_path, 'eta')
2448 svntest.main.file_append(eta_backup_path, "This is WC file 'eta'\n")
2450 svntest.main.run_svn(None, 'add', upsilon_backup_path, kappa_backup_path,
2451 epsilon_backup_path, zeta_backup_path, I_backup_path)
2453 # Set prop that will conflict with add from repos.
2454 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-WC',
2455 kappa_backup_path)
2456 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-WC',
2457 zeta_backup_path)
2458 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-WC',
2459 J_backup_path)
2461 # Set prop that will match add from repos.
2462 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-SAME',
2463 epsilon_backup_path)
2464 svntest.main.run_svn(None, 'propset', 'propname1', 'propval-SAME',
2465 K_backup_path)
2467 # Create expected output tree for an update of the wc_backup.
2468 expected_output = wc.State(wc_backup, {
2469 'A/B/upsilon' : Item(status='E '),
2470 'A/C/nu' : Item(status='A '),
2471 'A/D/H/I' : Item(status='E '),
2472 'A/D/H/I/J' : Item(status='EC'),
2473 'A/D/H/I/J/eta' : Item(status='C '),
2474 'A/D/H/I/K' : Item(status='EG'),
2475 'A/D/H/I/K/xi' : Item(status='E '),
2476 'A/D/H/I/L' : Item(status='A '),
2477 'A/D/kappa' : Item(status='CC'),
2478 'A/D/epsilon' : Item(status='CG'),
2479 'A/D/zeta' : Item(status='EC'),
2482 # Create expected disk for update of wc_backup.
2483 expected_disk = svntest.main.greek_state.copy()
2484 expected_disk.add({
2485 'A/B/upsilon' : Item("This is the file 'upsilon'\n"),
2486 'A/C/nu' : Item("This is the file 'nu'\n"),
2487 'A/D/H/I' : Item(),
2488 'A/D/H/I/J' : Item(props={'propname1' : 'propval-WC'}),
2489 'A/D/H/I/J/eta' : Item("\n".join(["<<<<<<< .mine",
2490 "This is WC file 'eta'",
2491 "=======",
2492 "This is REPOS file 'eta'",
2493 ">>>>>>> .r2",
2494 ""])),
2495 'A/D/H/I/K' : Item(props={'propname1' : 'propval-SAME'}),
2496 'A/D/H/I/K/xi' : Item("This is the file 'xi'\n"),
2497 'A/D/H/I/L' : Item(),
2498 'A/D/kappa' : Item("\n".join(["<<<<<<< .mine",
2499 "This is WC file 'kappa'",
2500 "=======",
2501 "This is REPOS file 'kappa'",
2502 ">>>>>>> .r2",
2503 ""]),
2504 props={'propname1' : 'propval-WC'}),
2505 'A/D/epsilon' : Item("\n".join(["<<<<<<< .mine",
2506 "This is WC file 'epsilon'",
2507 "=======",
2508 "This is REPOS file 'epsilon'",
2509 ">>>>>>> .r2",
2510 ""]),
2511 props={'propname1' : 'propval-SAME'}),
2512 'A/D/zeta' : Item("This is the file 'zeta'\n",
2513 props={'propname1' : 'propval-WC'}),
2516 # Create expected status tree for the update. Since the obstructing
2517 # kappa and upsilon differ from the repos, they should show as modified.
2518 expected_status = svntest.actions.get_virginal_state(wc_backup, 2)
2519 expected_status.add({
2520 'A/B/upsilon' : Item(status=' ', wc_rev=2),
2521 'A/C/nu' : Item(status=' ', wc_rev=2),
2522 'A/D/H/I' : Item(status=' ', wc_rev=2),
2523 'A/D/H/I/J' : Item(status=' C', wc_rev=2),
2524 'A/D/H/I/J/eta' : Item(status='C ', wc_rev=2),
2525 'A/D/H/I/K' : Item(status=' ', wc_rev=2),
2526 'A/D/H/I/K/xi' : Item(status=' ', wc_rev=2),
2527 'A/D/H/I/L' : Item(status=' ', wc_rev=2),
2528 'A/D/kappa' : Item(status='CC', wc_rev=2),
2529 'A/D/epsilon' : Item(status='C ', wc_rev=2),
2530 'A/D/zeta' : Item(status=' C', wc_rev=2),
2533 # "Extra" files that we expect to result from the conflicts.
2534 extra_files = ['eta\.r0', 'eta\.r2', 'eta\.mine',
2535 'kappa\.r0', 'kappa\.r2', 'kappa\.mine',
2536 'epsilon\.r0', 'epsilon\.r2', 'epsilon\.mine',
2537 'kappa.prej', 'zeta.prej', 'dir_conflicts.prej']
2539 # Perform forced update and check the results in three
2540 # ways (including props).
2541 svntest.actions.run_and_verify_update(wc_backup,
2542 expected_output,
2543 expected_disk,
2544 expected_status,
2545 None,
2546 svntest.tree.detect_conflict_files,
2547 extra_files, None, None, 1,
2548 wc_backup)
2550 # Some obstructions are still not permitted:
2552 # Test that file and dir obstructions scheduled for addition *with*
2553 # history fail when update tries to add the same path.
2555 # URL to URL copy of A/D/G to A/M.
2556 G_URL = sbox.repo_url + '/A/D/G'
2557 M_URL = sbox.repo_url + '/A/M'
2558 svntest.actions.run_and_verify_svn("Copy error:", None, [],
2559 'cp', G_URL, M_URL, '-m', '')
2561 # WC to WC copy of A/D/H to A/M, M now scheduled for addition with
2562 # history in WC and pending addition from the repos.
2563 H_path = os.path.join(wc_dir, 'A', 'D', 'H')
2564 A_path = os.path.join(wc_dir, 'A')
2565 M_path = os.path.join(wc_dir, 'A', 'M')
2567 svntest.actions.run_and_verify_svn("Copy error:", None, [],
2568 'cp', H_path, M_path)
2570 # URL to URL copy of A/D/H/omega to omicron.
2571 omega_URL = sbox.repo_url + '/A/D/H/omega'
2572 omicron_URL = sbox.repo_url + '/omicron'
2573 svntest.actions.run_and_verify_svn("Copy error:", None, [],
2574 'cp', omega_URL, omicron_URL,
2575 '-m', '')
2577 # WC to WC copy of A/D/H/chi to omicron, omicron now scheduled for
2578 # addition with history in WC and pending addition from the repos.
2579 chi_path = os.path.join(wc_dir, 'A', 'D', 'H', 'chi')
2580 omicron_path = os.path.join(wc_dir, 'omicron')
2582 svntest.actions.run_and_verify_svn("Copy error:", None, [],
2583 'cp', chi_path,
2584 omicron_path)
2586 # Try to update M's Parent.
2587 svntest.actions.run_and_verify_update(A_path, expected_output,
2588 expected_disk, expected_status,
2589 "svn: Failed to add " \
2590 "directory '.*M': a versioned " \
2591 "directory of the same name " \
2592 "already exists",
2593 None, None, None, None, 0)
2595 # --force shouldn't help either.
2596 svntest.actions.run_and_verify_update(wc_dir, expected_output,
2597 expected_disk, expected_status,
2598 "svn: Failed to add " \
2599 "directory '.*M': a versioned " \
2600 "directory of the same name " \
2601 "already exists",
2602 None, None, None, None, 0,
2603 A_path, '--force')
2605 # Try to update omicron's parent, non-recusively so as not to
2606 # try and update M first.
2607 svntest.actions.run_and_verify_update(wc_dir, expected_output,
2608 expected_disk, expected_status,
2609 "Failed to add file '.*omicron': " \
2610 "a file of the same name is " \
2611 "already scheduled for addition " \
2612 "with history",
2613 None, None, None, None, 0,
2614 wc_dir, '-N')
2616 # Again, --force shouldn't matter.
2617 svntest.actions.run_and_verify_update(wc_dir, expected_output,
2618 expected_disk, expected_status,
2619 "Failed to add file '.*omicron': " \
2620 "a file of the same name is " \
2621 "already scheduled for addition " \
2622 "with history",
2623 None, None, None, None, 0,
2624 wc_dir, '-N', '--force')
2626 # Test for issue #2022: Update shouldn't touch conflicted files.
2627 def update_conflicted(sbox):
2628 "update conflicted files"
2629 sbox.build()
2630 wc_dir = sbox.wc_dir
2631 iota_path = os.path.join(wc_dir, 'iota')
2632 lambda_path = os.path.join(wc_dir, 'A', 'B', 'lambda')
2633 mu_path = os.path.join(wc_dir, 'A', 'mu')
2634 D_path = os.path.join(wc_dir, 'A', 'D')
2635 pi_path = os.path.join(wc_dir, 'A', 'D', 'G', 'pi')
2637 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
2639 # Make some modifications to the files and a dir, creating r2.
2640 svntest.main.file_append(iota_path, 'Original appended text for iota\n')
2641 svntest.main.run_svn(None, 'propset', 'prop', 'val', lambda_path)
2642 svntest.main.file_append(mu_path, 'Original appended text for mu\n')
2643 svntest.main.run_svn(None, 'propset', 'prop', 'val', mu_path)
2644 svntest.main.run_svn(None, 'propset', 'prop', 'val', D_path)
2645 expected_output = svntest.wc.State(wc_dir, {
2646 'iota' : Item(verb='Sending'),
2647 'A/mu': Item(verb='Sending'),
2648 'A/B/lambda': Item(verb='Sending'),
2649 'A/D': Item(verb='Sending'),
2652 expected_status.tweak('iota', 'A/mu', 'A/B/lambda', 'A/D', wc_rev=2)
2653 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2654 expected_status, None, wc_dir)
2656 # Do another change to each path that we will need later.
2657 # Also, change a file below A/D in the path.
2658 svntest.main.file_append(iota_path, 'Another line for iota\n')
2659 svntest.main.file_append(mu_path, 'Another line for mu\n')
2660 svntest.main.file_append(lambda_path, 'Another line for lambda\n')
2661 svntest.main.run_svn(None, 'propset', 'prop', 'val2', D_path)
2662 svntest.main.file_append(pi_path, 'Another line for pi\n')
2663 expected_status.tweak('iota', 'A/mu', 'A/B/lambda', 'A/D', 'A/D/G/pi',
2664 wc_rev=3)
2665 expected_output.add({
2666 'A/D/G/pi': Item(verb='Sending')})
2667 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2668 expected_status, None, wc_dir)
2670 # Go back to revision 1.
2671 expected_output = svntest.wc.State(wc_dir, {
2672 'iota' : Item(status='U '),
2673 'A/B/lambda' : Item(status='UU'),
2674 'A/mu' : Item(status='UU'),
2675 'A/D': Item(status=' U'),
2676 'A/D/G/pi': Item(status='U '),
2678 expected_disk = svntest.main.greek_state.copy()
2679 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
2680 svntest.actions.run_and_verify_update(wc_dir,
2681 expected_output,
2682 expected_disk,
2683 expected_status,
2684 None,
2685 None, None,
2686 None, None, 1,
2687 '-r1', wc_dir)
2689 # Create modifications conflicting with rev 2.
2690 svntest.main.file_append(iota_path, 'Conflicting appended text for iota\n')
2691 svntest.main.run_svn(None, 'propset', 'prop', 'conflictval', lambda_path)
2692 svntest.main.file_append(mu_path, 'Conflicting appended text for mu\n')
2693 svntest.main.run_svn(None, 'propset', 'prop', 'conflictval', mu_path)
2694 svntest.main.run_svn(None, 'propset', 'prop', 'conflictval', D_path)
2696 # Update to revision 2, expecting conflicts.
2697 expected_output = svntest.wc.State(wc_dir, {
2698 'iota': Item(status='C '),
2699 'A/B/lambda': Item(status=' C'),
2700 'A/mu': Item(status='CC'),
2701 'A/D': Item(status=' C'),
2703 expected_disk.tweak('iota',
2704 contents="\n".join(["This is the file 'iota'.",
2705 "<<<<<<< .mine",
2706 "Conflicting appended text for iota",
2707 "=======",
2708 "Original appended text for iota",
2709 ">>>>>>> .r2",
2710 ""]))
2711 expected_disk.tweak('A/mu',
2712 contents="\n".join(["This is the file 'mu'.",
2713 "<<<<<<< .mine",
2714 "Conflicting appended text for mu",
2715 "=======",
2716 "Original appended text for mu",
2717 ">>>>>>> .r2",
2718 ""]),
2719 props={'prop': 'conflictval'})
2720 expected_disk.tweak('A/B/lambda', 'A/D', props={'prop': 'conflictval'})
2722 expected_status.tweak(wc_rev=2)
2723 expected_status.tweak('iota', status='C ')
2724 expected_status.tweak('A/B/lambda', 'A/D', status=' C')
2725 expected_status.tweak('A/mu', status='CC')
2726 extra_files = [ [wc_dir, 'iota.*\.(r1|r2|mine)'],
2727 [wc_dir, 'mu.*\.(r1|r2|mine|prej)'],
2728 [wc_dir, 'lambda.*\.prej'],
2729 [wc_dir, 'dir_conflicts.prej']]
2730 svntest.actions.run_and_verify_update(wc_dir,
2731 expected_output,
2732 expected_disk,
2733 expected_status,
2734 None,
2735 detect_extra_files, extra_files,
2736 None, None, 1,
2737 '-r2', wc_dir)
2739 # Now, update to HEAD, which should skip all the conflicted files, but
2740 # still update the pi file.
2741 expected_output = svntest.wc.State(wc_dir, {
2742 'iota' : Item(verb='Skipped'),
2743 'A/B/lambda' : Item(verb='Skipped'),
2744 'A/mu' : Item(verb='Skipped'),
2745 'A/D' : Item(verb='Skipped'),
2746 'A/D/G/pi' : Item(status='U '),
2748 expected_status.tweak(wc_rev=3)
2749 expected_status.tweak('iota', 'A/B/lambda', 'A/mu', 'A/D', wc_rev=2)
2750 expected_disk.tweak('A/D/G/pi', contents="""This is the file 'pi'.
2751 Another line for pi
2752 """)
2753 svntest.actions.run_and_verify_update(wc_dir,
2754 expected_output,
2755 expected_disk,
2756 expected_status,
2757 None,
2758 detect_extra_files, extra_files,
2759 None, None, 1)
2761 #----------------------------------------------------------------------
2762 def mergeinfo_update_elision(sbox):
2763 "mergeinfo does not elide after update"
2765 # No mergeinfo elision is performed when doing updates. So updates may
2766 # result in equivalent mergeinfo on a path and it's nearest working copy
2767 # parent with explicit mergeinfo. This is currently permitted and
2768 # honestly we could probably do without this test(?).
2770 # Search for the comment entitled "The Merge Kluge" in merge_tests.py
2771 # to understand why we shorten, and subsequently chdir() after calling
2772 # this function.
2773 def shorten_path_kludge(path):
2774 shorten_by = len(svntest.main.work_dir) + len(os.sep)
2775 return path[shorten_by:]
2777 sbox.build()
2778 wc_dir = sbox.wc_dir
2780 # Some paths we'll care about
2781 alpha_COPY_path = os.path.join(wc_dir, "A", "B_COPY", "E", "alpha")
2782 alpha_path = os.path.join(wc_dir, "A", "B", "E", "alpha")
2783 B_COPY_path = os.path.join(wc_dir, "A", "B_COPY")
2784 E_COPY_path = os.path.join(wc_dir, "A", "B_COPY", "E")
2785 beta_path = os.path.join(wc_dir, "A", "B", "E", "beta")
2786 lambda_path = os.path.join(wc_dir, "A", "B", "lambda")
2788 # Make a branch A/B_COPY
2789 svntest.actions.run_and_verify_svn(
2790 None,
2791 ["A " + os.path.join(wc_dir, "A", "B_COPY", "lambda") + "\n",
2792 "A " + os.path.join(wc_dir, "A", "B_COPY", "E") + "\n",
2793 "A " + os.path.join(wc_dir, "A", "B_COPY", "E", "alpha") + "\n",
2794 "A " + os.path.join(wc_dir, "A", "B_COPY", "E", "beta") + "\n",
2795 "A " + os.path.join(wc_dir, "A", "B_COPY", "F") + "\n",
2796 "Checked out revision 1.\n",
2797 "A " + B_COPY_path + "\n"],
2799 'copy',
2800 sbox.repo_url + "/A/B",
2801 B_COPY_path)
2803 expected_output = wc.State(wc_dir, {'A/B_COPY' : Item(verb='Adding')})
2804 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
2805 expected_status.add({
2806 "A/B_COPY" : Item(status=' ', wc_rev=2),
2807 "A/B_COPY/lambda" : Item(status=' ', wc_rev=2),
2808 "A/B_COPY/E" : Item(status=' ', wc_rev=2),
2809 "A/B_COPY/E/alpha" : Item(status=' ', wc_rev=2),
2810 "A/B_COPY/E/beta" : Item(status=' ', wc_rev=2),
2811 "A/B_COPY/F" : Item(status=' ', wc_rev=2),})
2813 svntest.actions.run_and_verify_commit(wc_dir,
2814 expected_output,
2815 expected_status,
2816 None,
2817 wc_dir)
2819 # Make some changes under A/B
2821 # r3 - modify and commit A/B/E/beta
2822 svntest.main.file_write(beta_path, "New content")
2823 expected_output = wc.State(wc_dir, {'A/B/E/beta' : Item(verb='Sending')})
2824 expected_status.tweak('A/B/E/beta', wc_rev=3)
2825 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2826 expected_status, None, wc_dir)
2828 # r4 - modify and commit A/B/lambda
2829 svntest.main.file_write(lambda_path, "New content")
2830 expected_output = wc.State(wc_dir, {'A/B/lambda' : Item(verb='Sending')})
2831 expected_status.tweak('A/B/lambda', wc_rev=4)
2832 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2833 expected_status, None, wc_dir)
2835 # r5 - modify and commit A/B/E/alpha
2836 svntest.main.file_write(alpha_path, "New content")
2837 expected_output = wc.State(wc_dir, {'A/B/E/alpha' : Item(verb='Sending')})
2838 expected_status.tweak('A/B/E/alpha', wc_rev=5)
2839 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2840 expected_status, None, wc_dir)
2842 # Merge r2:5 into A/B_COPY
2843 # Search for the comment entitled "The Merge Kluge" in merge_tests.py,
2844 # to understand why we shorten and chdir() below.
2845 short_B_COPY_path = shorten_path_kludge(B_COPY_path)
2846 expected_output = wc.State(short_B_COPY_path, {
2847 'lambda' : Item(status='U '),
2848 'E/alpha' : Item(status='U '),
2849 'E/beta' : Item(status='U '),
2851 expected_merge_status = wc.State(short_B_COPY_path, {
2852 '' : Item(status=' M', wc_rev=2),
2853 'lambda' : Item(status='M ', wc_rev=2),
2854 'E' : Item(status=' ', wc_rev=2),
2855 'E/alpha' : Item(status='M ', wc_rev=2),
2856 'E/beta' : Item(status='M ', wc_rev=2),
2857 'F' : Item(status=' ', wc_rev=2),
2859 expected_merge_disk = wc.State('', {
2860 '' : Item(props={SVN_PROP_MERGEINFO : '/A/B:3-5'}),
2861 'lambda' : Item("New content"),
2862 'E' : Item(),
2863 'E/alpha' : Item("New content"),
2864 'E/beta' : Item("New content"),
2865 'F' : Item(),
2867 expected_skip = wc.State(short_B_COPY_path, { })
2868 saved_cwd = os.getcwd()
2870 os.chdir(svntest.main.work_dir)
2871 svntest.actions.run_and_verify_merge(short_B_COPY_path, '2', '5',
2872 sbox.repo_url + \
2873 '/A/B',
2874 expected_output,
2875 expected_merge_disk,
2876 expected_merge_status,
2877 expected_skip,
2878 None, None, None, None,
2879 None, 1)
2880 os.chdir(saved_cwd)
2882 # r6 - Commit the merge
2883 expected_output = wc.State(wc_dir,
2884 {'A/B_COPY' : Item(verb='Sending'),
2885 'A/B_COPY/E/alpha' : Item(verb='Sending'),
2886 'A/B_COPY/E/beta' : Item(verb='Sending'),
2887 'A/B_COPY/lambda' : Item(verb='Sending')})
2888 expected_status.tweak('A/B_COPY', wc_rev=6)
2889 expected_status.tweak('A/B_COPY/E/alpha', wc_rev=6)
2890 expected_status.tweak('A/B_COPY/E/beta', wc_rev=6)
2891 expected_status.tweak('A/B_COPY/lambda', wc_rev=6)
2892 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2893 expected_status, None, wc_dir)
2895 # Update WC back to r5, A/COPY_B is at it's pre-merge state again
2896 expected_output = wc.State(wc_dir,
2897 {'A/B_COPY' : Item(status=' U'),
2898 'A/B_COPY/E/alpha' : Item(status='U '),
2899 'A/B_COPY/E/beta' : Item(status='U '),
2900 'A/B_COPY/lambda' : Item(status='U '),})
2901 expected_status.tweak(wc_rev=5)
2902 expected_disk = svntest.main.greek_state.copy()
2903 expected_disk.add({
2904 'A/B_COPY' : Item(),
2905 'A/B_COPY/lambda' : Item("This is the file 'lambda'.\n"),
2906 'A/B_COPY/E' : Item(),
2907 'A/B_COPY/E/alpha' : Item("This is the file 'alpha'.\n"),
2908 'A/B_COPY/E/beta' : Item("This is the file 'beta'.\n"),
2909 'A/B_COPY/F' : Item(),
2911 expected_disk.tweak('A/B/lambda', contents="New content")
2912 expected_disk.tweak('A/B/E/alpha', contents="New content")
2913 expected_disk.tweak('A/B/E/beta', contents="New content")
2914 svntest.actions.run_and_verify_update(wc_dir,
2915 expected_output,
2916 expected_disk,
2917 expected_status,
2918 None, None, None,
2919 None, None, 1,
2920 '-r', '5', wc_dir)
2922 # Merge r2:5 to A/B_COPY/E/alpha
2923 short_alpha_COPY_path = shorten_path_kludge(alpha_COPY_path)
2924 expected_output = wc.State(short_alpha_COPY_path, {
2925 'alpha' : Item(status='U '),
2927 expected_skip = wc.State(short_alpha_COPY_path, { })
2928 saved_cwd = os.getcwd()
2930 os.chdir(svntest.main.work_dir)
2931 # run_and_verify_merge doesn't support merging to a file WCPATH
2932 # so use run_and_verify_svn.
2933 update_line = 'U ' + short_alpha_COPY_path + '\n'
2934 if sys.platform == 'win32':
2935 # Construct a properly escaped regex when dealing with
2936 # '\' riddled paths on Windows.
2937 update_line = update_line.replace("\\", "\\\\")
2938 svntest.actions.run_and_verify_svn(None,
2939 '|'.join(
2940 [svntest.main.merge_notify_line(3, 5),
2941 update_line]),
2942 [], 'merge', '-r2:5',
2943 sbox.repo_url + '/A/B/E/alpha',
2944 short_alpha_COPY_path)
2946 os.chdir(saved_cwd)
2948 expected_alpha_status = wc.State(alpha_COPY_path, {
2949 '' : Item(status='MM', wc_rev=5),
2951 svntest.actions.run_and_verify_status(alpha_COPY_path,
2952 expected_alpha_status)
2954 svntest.actions.run_and_verify_svn(None, ["/A/B/E/alpha:3-5\n"], [],
2955 'propget', SVN_PROP_MERGEINFO,
2956 alpha_COPY_path)
2958 # Update WC. The local mergeinfo (r3-5) on A/B_COPY/E/alpha is
2959 # identical to that on added to A/B_COPY by the update, but update
2960 # doesn't support elision so this redundancy is permitted.
2961 expected_output = wc.State(wc_dir, {
2962 'A/B_COPY/lambda' : Item(status='U '),
2963 'A/B_COPY/E/alpha' : Item(status='G '),
2964 'A/B_COPY/E/beta' : Item(status='U '),
2965 'A/B_COPY' : Item(status=' U'),
2967 expected_disk.tweak('A/B_COPY', props={SVN_PROP_MERGEINFO : '/A/B:3-5'})
2968 expected_disk.tweak('A/B_COPY/lambda', contents="New content")
2969 expected_disk.tweak('A/B_COPY/E/beta', contents="New content")
2970 expected_disk.tweak('A/B_COPY/E/alpha', contents="New content",
2971 props={SVN_PROP_MERGEINFO : '/A/B/E/alpha:3-5'})
2972 expected_status.tweak(wc_rev=6)
2973 expected_status.tweak('A/B_COPY/E/alpha', status=' M')
2974 svntest.actions.run_and_verify_update(wc_dir,
2975 expected_output,
2976 expected_disk,
2977 expected_status,
2978 None, None, None,
2979 None, None, 1)
2981 # Now test that an updated target's mergeinfo can itself elide.
2982 # r7 - modify and commit A/B/E/alpha
2983 svntest.main.file_write(alpha_path, "More new content")
2984 expected_output = wc.State(wc_dir, {
2985 'A/B/E/alpha' : Item(verb='Sending'),
2986 'A/B_COPY/E/alpha' : Item(verb='Sending')})
2987 expected_status.tweak('A/B/E/alpha', 'A/B_COPY/E/alpha', status=' ',
2988 wc_rev=7)
2989 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
2990 expected_status, None, wc_dir)
2992 # Update A to get all paths to the same working revision.
2993 svntest.actions.run_and_verify_svn(None, ["At revision 7.\n"], [],
2994 'up', wc_dir)
2996 # Merge r6:7 into A/B_COPY/E
2997 short_E_COPY_path = shorten_path_kludge(E_COPY_path)
2998 expected_output = wc.State(short_E_COPY_path, {
2999 'alpha' : Item(status='U '),
3001 expected_merge_status = wc.State(short_E_COPY_path, {
3002 '' : Item(status=' M', wc_rev=7),
3003 'alpha' : Item(status='MM', wc_rev=7),
3004 'beta' : Item(status=' ', wc_rev=7),
3006 expected_merge_disk = wc.State('', {
3007 '' : Item(props={SVN_PROP_MERGEINFO : '/A/B/E:3-5,7'}),
3008 'alpha' : Item("More new content"),
3009 'beta' : Item("New content"),
3011 expected_skip = wc.State(short_E_COPY_path, { })
3012 saved_cwd = os.getcwd()
3014 os.chdir(svntest.main.work_dir)
3015 svntest.actions.run_and_verify_merge(short_E_COPY_path, '6', '7',
3016 sbox.repo_url + \
3017 '/A/B/E',
3018 expected_output,
3019 expected_merge_disk,
3020 expected_merge_status,
3021 expected_skip,
3022 None, None, None, None,
3023 None, 1)
3025 os.chdir(saved_cwd)
3027 # r8 - Commit the merge
3028 svntest.actions.run_and_verify_svn(None,
3029 ["At revision 7.\n"],
3030 [], 'update', wc_dir)
3031 expected_output = wc.State(wc_dir,
3032 {'A/B_COPY/E' : Item(verb='Sending'),
3033 'A/B_COPY/E/alpha' : Item(verb='Sending')})
3034 expected_status.tweak(wc_rev=7)
3035 expected_status.tweak('A/B_COPY/E', 'A/B_COPY/E/alpha', wc_rev=8)
3036 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
3037 expected_status, None, wc_dir)
3039 # Update A/COPY_B/E back to r7
3040 expected_output = wc.State(wc_dir, {
3041 'A/B_COPY/E/alpha' : Item(status='UU'),
3042 'A/B_COPY/E' : Item(status=' U'),
3044 expected_status.tweak(wc_rev=7)
3045 expected_disk.tweak('A/B_COPY',
3046 props={SVN_PROP_MERGEINFO : '/A/B:3-5'})
3047 expected_disk.tweak('A/B/E/alpha', contents="More new content")
3048 expected_disk.tweak('A/B_COPY/E/alpha', contents="New content")
3050 svntest.actions.run_and_verify_update(wc_dir,
3051 expected_output,
3052 expected_disk,
3053 expected_status,
3054 None, None, None,
3055 None, None, 1,
3056 '-r', '7', E_COPY_path)
3058 # Merge r6:7 to A/B_COPY
3059 short_B_COPY_path = shorten_path_kludge(B_COPY_path)
3060 expected_output = wc.State(short_B_COPY_path, {
3061 'E/alpha' : Item(status='U '),
3063 expected_merge_status = wc.State(short_B_COPY_path, {
3064 '' : Item(status=' M', wc_rev=7),
3065 'lambda' : Item(status=' ', wc_rev=7),
3066 'E' : Item(status=' ', wc_rev=7),
3067 'E/alpha' : Item(status='MM', wc_rev=7),
3068 'E/beta' : Item(status=' ', wc_rev=7),
3069 'F' : Item(status=' ', wc_rev=7),
3071 expected_merge_disk = wc.State('', {
3072 '' : Item(props={SVN_PROP_MERGEINFO : '/A/B:3-5,7'}),
3073 'lambda' : Item("New content"),
3074 'E' : Item(),
3075 'E/alpha' : Item("More new content"),
3076 'E/beta' : Item("New content"),
3077 'F' : Item(),
3079 expected_skip = wc.State(short_B_COPY_path, { })
3080 saved_cwd = os.getcwd()
3082 os.chdir(svntest.main.work_dir)
3083 svntest.actions.run_and_verify_merge(short_B_COPY_path, '6', '7',
3084 sbox.repo_url + \
3085 '/A/B',
3086 expected_output,
3087 expected_merge_disk,
3088 expected_merge_status,
3089 expected_skip,
3090 None, None, None, None,
3091 None, 1,alpha_COPY_path)
3093 os.chdir(saved_cwd)
3095 # Update just A/B_COPY/E. The mergeinfo (r3-5,7) reset on
3096 # A/B_COPY/E by the udpate is identical to the local info on
3097 # A/B_COPY, so should elide, leaving no mereginfo on E.
3098 #expected_output = svntest.wc.State(wc_dir, { })
3099 expected_output = wc.State(wc_dir, {
3100 'A/B_COPY/E/alpha' : Item(status='GG'),
3101 'A/B_COPY/E/' : Item(status=' U'),
3103 expected_status.tweak('A/B_COPY', status=' M', wc_rev=7)
3104 expected_status.tweak('A/B_COPY/E', status=' ', wc_rev=8)
3105 expected_status.tweak('A/B_COPY/E/alpha', wc_rev=8)
3106 expected_status.tweak('A/B_COPY/E/beta', wc_rev=8)
3107 expected_disk.tweak('A/B_COPY',
3108 props={SVN_PROP_MERGEINFO : '/A/B:3-5,7'})
3109 expected_disk.tweak('A/B_COPY/E',
3110 props={SVN_PROP_MERGEINFO : '/A/B/E:3-5,7'})
3111 expected_disk.tweak('A/B_COPY/E/alpha', contents="More new content",
3112 props={})
3113 svntest.actions.run_and_verify_update(wc_dir,
3114 expected_output,
3115 expected_disk,
3116 expected_status,
3117 None, None, None,
3118 None, None, 1, E_COPY_path)
3121 #----------------------------------------------------------------------
3122 # If the update editor receives add_file(foo, copyfrom='blah'), it
3123 # should attempt to locate 'blah' in the wc, and then copy it into place.
3125 def update_handles_copyfrom(sbox):
3126 "update should make use of copyfrom args"
3128 sbox.build()
3129 wc_dir = sbox.wc_dir
3131 # Make a backup copy of the working copy.
3132 wc_backup = sbox.add_wc_path('backup')
3133 svntest.actions.duplicate_dir(wc_dir, wc_backup)
3135 # Copy 'rho' to 'glub'
3136 rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
3137 glub_path = os.path.join(wc_dir, 'A', 'D', 'G', 'glub')
3138 svntest.actions.run_and_verify_svn(None, None, [],
3139 'copy', rho_path, glub_path)
3141 # Commit that change, creating r2.
3142 expected_output = svntest.wc.State(wc_dir, {
3143 'A/D/G/glub' : Item(verb='Adding'),
3145 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
3146 expected_status.add({
3147 'A/D/G/glub' : Item(status=' ', wc_rev=2),
3149 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
3150 expected_status, None, wc_dir)
3152 # Make a local edits to rho in the backup working copy - both text and props
3153 rho2_path = os.path.join(wc_backup, 'A', 'D', 'G', 'rho')
3154 svntest.main.file_append(rho2_path, "Some new text.\n")
3155 svntest.main.run_svn(None, 'propset', 'Kubla', 'Khan', rho2_path)
3157 # Now try updating our backup working copy: it should receive glub,
3158 # but with copyfrom args of rho@1, and thus copy the existing
3159 # (edited) rho to glub. In other words, both rho and glub should be
3160 # identical and contain the same local edits.
3162 expected_output = svntest.wc.State(wc_backup, { })
3163 expected_output = wc.State(wc_backup, {
3164 'A/D/G/glub' : Item(status='A '), ### perhaps update should show 'A +' ??
3167 expected_disk = svntest.main.greek_state.copy()
3168 expected_disk.tweak('A/D/G/rho',
3169 contents="This is the file 'rho'.\nSome new text.\n",
3170 props={'Kubla' : 'Khan'})
3171 expected_disk.add({
3172 'A/D/G/glub' : Item("This is the file 'rho'.\nSome new text.\n",
3173 props={'Kubla' : 'Khan', 'svn:mergeinfo' : ''})
3176 expected_status = svntest.actions.get_virginal_state(wc_backup, 2)
3177 expected_status.tweak('A/D/G/rho', wc_rev=2, status='MM')
3178 expected_status.add({
3179 'A/D/G/glub' : Item(status='MM', wc_rev=2),
3181 svntest.actions.run_and_verify_update(wc_backup,
3182 expected_output,
3183 expected_disk,
3184 expected_status,
3185 check_props = True)
3187 #----------------------------------------------------------------------
3188 # if the update_editor receives add_file(copyfrom=...), and the
3189 # copyfrom_path simply isn't available in the working copy, it should
3190 # fall back to doing an RA request to fetch the file.
3192 def copyfrom_degrades_gracefully(sbox):
3193 "update degrades well if copyfrom_path unavailable"
3195 sbox.build()
3196 wc_dir = sbox.wc_dir
3198 # Make a backup copy of the working copy.
3199 wc_backup = sbox.add_wc_path('backup')
3200 svntest.actions.duplicate_dir(wc_dir, wc_backup)
3202 # Move 'alpha' to 'glub'
3203 alpha_path = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
3204 glub_path = os.path.join(wc_dir, 'A', 'D', 'G', 'glub')
3205 svntest.actions.run_and_verify_svn(None, None, [],
3206 'mv', alpha_path, glub_path)
3208 # Commit that change, creating r2.
3209 expected_output = svntest.wc.State(wc_dir, {
3210 'A/B/E/alpha' : Item(verb='Deleting'),
3211 'A/D/G/glub' : Item(verb='Adding'),
3213 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
3214 expected_status.add({
3215 'A/D/G/glub' : Item(status=' ', wc_rev=2),
3217 expected_status.remove('A/B/E/alpha')
3218 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
3219 expected_status, None, wc_dir)
3221 # In the 2nd working copy, update just one side of the move -- so that
3222 # alpha gets deleted, but glub not yet added.
3223 E_path = os.path.join(wc_backup, 'A', 'B', 'E')
3224 expected_output = svntest.wc.State(E_path, {
3225 'alpha' : Item(status='D '),
3227 expected_disk = wc.State('', {
3228 'beta' : wc.StateItem("This is the file 'beta'.\n"),
3230 expected_status = svntest.wc.State(E_path, {
3231 '' : Item(status=' '),
3232 'beta' : Item(status=' '),
3234 expected_status.tweak(wc_rev=2)
3235 svntest.actions.run_and_verify_update(E_path,
3236 expected_output,
3237 expected_disk,
3238 expected_status)
3240 # Now update the entire working copy, which should cause an
3241 # add_file(glub, copyfrom_path=alpha)... except alpha is already gone.
3242 # Update editor should gracefully fetch it via RA request.
3243 expected_output = svntest.wc.State(wc_backup, { })
3244 expected_output = wc.State(wc_backup, {
3245 'A/D/G/glub' : Item(status='A '),
3247 expected_disk = svntest.main.greek_state.copy()
3248 expected_disk.remove('A/B/E/alpha')
3249 expected_disk.add({
3250 'A/D/G/glub' : Item("This is the file 'alpha'.\n"),
3252 expected_status = svntest.actions.get_virginal_state(wc_backup, 2)
3253 expected_status.remove('A/B/E/alpha')
3254 expected_status.add({
3255 'A/D/G/glub' : Item(status=' ', wc_rev=2),
3257 svntest.actions.run_and_verify_update(wc_backup,
3258 expected_output,
3259 expected_disk,
3260 expected_status)
3262 #----------------------------------------------------------------------
3263 # If the update editor receives add_file(foo, copyfrom='blah'), it
3264 # should attempt to locate 'blah' in the wc, and then copy it into
3265 # place. Furthermore, the new file should be able to receive
3266 # subsequent txdeltas coming from the server.
3268 def update_handles_copyfrom_with_txdeltas(sbox):
3269 "update uses copyfrom & accepts further txdeltas"
3271 sbox.build()
3272 wc_dir = sbox.wc_dir
3274 # Make a backup copy of the working copy.
3275 wc_backup = sbox.add_wc_path('backup')
3276 svntest.actions.duplicate_dir(wc_dir, wc_backup)
3278 # Copy 'rho' to 'glub'
3279 rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
3280 glub_path = os.path.join(wc_dir, 'A', 'D', 'G', 'glub')
3281 svntest.actions.run_and_verify_svn(None, None, [],
3282 'copy', rho_path, glub_path)
3284 # Commit that change, creating r2.
3285 expected_output = svntest.wc.State(wc_dir, {
3286 'A/D/G/glub' : Item(verb='Adding'),
3288 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
3289 expected_status.add({
3290 'A/D/G/glub' : Item(status=' ', wc_rev=2),
3292 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
3293 expected_status, None, wc_dir)
3295 # Make additional edits to glub...
3296 svntest.main.file_append_binary(glub_path, "Some new text.\n")
3297 svntest.main.run_svn(None, 'propset', 'Kubla', 'Khan', glub_path)
3299 # Commit the changes, creating r3.
3300 expected_output = svntest.wc.State(wc_dir, {
3301 'A/D/G/glub' : Item(verb='Sending'),
3303 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
3304 expected_status.add({
3305 'A/D/G/glub' : Item(status=' ', wc_rev=3),
3307 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
3308 expected_status, None, wc_dir)
3310 # Make a local edit to rho in the backup working copy.
3311 rho2_path = os.path.join(wc_backup, 'A', 'D', 'G', 'rho')
3312 svntest.main.file_write(rho2_path,
3313 "New first line.\nThis is the file 'rho'.\n",
3314 "wb")
3316 # Now try updating our backup working copy: it should receive glub,
3317 # but with copyfrom args of rho@1, and thus copy the existing rho to
3318 # glub. Furthermore, it should then apply the extra r3 edits to the
3319 # copied file.
3321 expected_output = svntest.wc.State(wc_backup, { })
3322 expected_output = wc.State(wc_backup, {
3323 'A/D/G/glub' : Item(status='A '), ### perhaps update should show 'A +' ??
3326 expected_disk = svntest.main.greek_state.copy()
3327 expected_disk.tweak('A/D/G/rho',
3328 contents="New first line.\nThis is the file 'rho'.\n")
3329 expected_disk.add({
3330 'A/D/G/glub' : Item("New first line.\nThis is the file 'rho'.\nSome new text.\n",
3331 props={'Kubla' : 'Khan', 'svn:mergeinfo' : ''})
3334 expected_status = svntest.actions.get_virginal_state(wc_backup, 3)
3335 expected_status.tweak('A/D/G/rho', wc_rev=3, status='M ')
3336 expected_status.add({
3337 'A/D/G/glub' : Item(status='M ', wc_rev=3),
3339 svntest.actions.run_and_verify_update(wc_backup,
3340 expected_output,
3341 expected_disk,
3342 expected_status,
3343 check_props = True)
3345 #----------------------------------------------------------------------
3346 # Very obscure bug: Issue #2977.
3347 # Let's say there's a revision with
3348 # $ svn mv b c
3349 # $ svn mv a b
3350 # $ svn ci
3351 # and a later revision that modifies b. We then try a fresh checkout. If
3352 # the server happens to send us 'b' first, then when it later gets 'c'
3353 # (with a copyfrom of 'b') it might try to use the 'b' in the wc as the
3354 # copyfrom base. This is wrong, because 'b' was changed later; however,
3355 # due to a bug, the setting of svn:entry:committed-rev on 'b' is not being
3356 # properly seen by the client, and it chooses the wrong base. Corruption!
3358 # Note that because this test depends on the order that the server sends
3359 # changes, it is very fragile; even changing the file names can avoid
3360 # triggering the bug.
3362 def update_copied_from_replaced_and_changed(sbox):
3363 "update chooses right copyfrom for double move"
3365 sbox.build()
3366 wc_dir = sbox.wc_dir
3368 fn1_relpath = os.path.join('A', 'B', 'E', 'aardvark')
3369 fn2_relpath = os.path.join('A', 'B', 'E', 'alpha')
3370 fn3_relpath = os.path.join('A', 'B', 'E', 'beta')
3371 fn1_path = os.path.join(wc_dir, fn1_relpath)
3372 fn2_path = os.path.join(wc_dir, fn2_relpath)
3373 fn3_path = os.path.join(wc_dir, fn3_relpath)
3375 # Move fn2 to fn1
3376 svntest.actions.run_and_verify_svn(None, None, [],
3377 'mv', fn2_path, fn1_path)
3379 # Move fn3 to fn2
3380 svntest.actions.run_and_verify_svn(None, None, [],
3381 'mv', fn3_path, fn2_path)
3383 # Commit that change, creating r2.
3384 expected_output = svntest.wc.State(wc_dir, {
3385 fn1_relpath : Item(verb='Adding'),
3386 fn2_relpath : Item(verb='Replacing'),
3387 fn3_relpath : Item(verb='Deleting'),
3389 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
3390 expected_status.remove(fn2_relpath, fn3_relpath)
3391 expected_status.add({
3392 fn1_relpath : Item(status=' ', wc_rev=2),
3393 fn2_relpath : Item(status=' ', wc_rev=2),
3395 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
3396 expected_status, None, wc_dir)
3398 # Modify fn2.
3399 fn2_final_contents = "I have new contents for the middle file."
3400 svntest.main.file_write(fn2_path, fn2_final_contents)
3402 # Commit the changes, creating r3.
3403 expected_output = svntest.wc.State(wc_dir, {
3404 fn2_relpath : Item(verb='Sending'),
3406 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
3407 expected_status.remove(fn2_relpath, fn3_relpath)
3408 expected_status.add({
3409 fn1_relpath : Item(status=' ', wc_rev=2),
3410 fn2_relpath : Item(status=' ', wc_rev=3),
3412 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
3413 expected_status, None, wc_dir)
3415 # Go back to r1.
3416 expected_output = svntest.wc.State(wc_dir, {
3417 fn1_relpath: Item(status='D '),
3418 fn2_relpath: Item(status='A '), # though actually should be D and A
3419 fn3_relpath: Item(status='A '),
3421 # Create expected disk tree for the update to rev 0
3422 expected_disk = svntest.main.greek_state.copy()
3423 # Do the update and check the results.
3424 svntest.actions.run_and_verify_update(wc_dir,
3425 expected_output,
3426 expected_disk,
3427 None, None,
3428 None, None, None, None, 0,
3429 '-r', '1', wc_dir)
3431 # And back up to 3 again.
3432 expected_output = svntest.wc.State(wc_dir, {
3433 fn1_relpath: Item(status='A '),
3434 fn2_relpath: Item(status='A '), # though actually should be D and A
3435 fn3_relpath: Item(status='D '),
3437 # Create expected disk tree for the update to rev 0
3438 expected_disk = svntest.main.greek_state.copy()
3439 expected_disk.add({
3440 fn1_relpath : Item("This is the file 'alpha'.\n"),
3442 expected_disk.tweak(fn2_relpath, contents=fn2_final_contents)
3443 expected_disk.remove(fn3_relpath)
3444 # reuse old expected_status, but at r3
3445 expected_status.tweak(wc_rev=3)
3446 svntest.actions.run_and_verify_update(wc_dir,
3447 expected_output,
3448 expected_disk,
3449 expected_status, None,
3450 None, None, None, None, 0,
3451 wc_dir)
3454 #----------------------------------------------------------------------
3457 def update_accept_conflicts(sbox):
3458 "update --accept automatic conflict resolution"
3460 sbox.build()
3461 wc_dir = sbox.wc_dir
3463 # Make a backup copy of the working copy
3464 wc_backup = sbox.add_wc_path('backup')
3465 svntest.actions.duplicate_dir(wc_dir, wc_backup)
3467 # Make a few local mods to files which will be committed
3468 iota_path = os.path.join(wc_dir, 'iota')
3469 lambda_path = os.path.join(wc_dir, 'A', 'B', 'lambda')
3470 mu_path = os.path.join(wc_dir, 'A', 'mu')
3471 alpha_path = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
3472 beta_path = os.path.join(wc_dir, 'A', 'B', 'E', 'beta')
3473 pi_path = os.path.join(wc_dir, 'A', 'D', 'G', 'pi')
3474 rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
3475 svntest.main.file_append(lambda_path, 'Their appended text for lambda\n')
3476 svntest.main.file_append(iota_path, 'Their appended text for iota\n')
3477 svntest.main.file_append(mu_path, 'Their appended text for mu\n')
3478 svntest.main.file_append(alpha_path, 'Their appended text for alpha\n')
3479 svntest.main.file_append(beta_path, 'Their appended text for beta\n')
3480 svntest.main.file_append(pi_path, 'Their appended text for pi\n')
3481 svntest.main.file_append(rho_path, 'Their appended text for rho\n')
3483 # Make a few local mods to files which will be conflicted
3484 iota_path_backup = os.path.join(wc_backup, 'iota')
3485 lambda_path_backup = os.path.join(wc_backup, 'A', 'B', 'lambda')
3486 mu_path_backup = os.path.join(wc_backup, 'A', 'mu')
3487 alpha_path_backup = os.path.join(wc_backup, 'A', 'B', 'E', 'alpha')
3488 beta_path_backup = os.path.join(wc_backup, 'A', 'B', 'E', 'beta')
3489 pi_path_backup = os.path.join(wc_backup, 'A', 'D', 'G', 'pi')
3490 rho_path_backup = os.path.join(wc_backup, 'A', 'D', 'G', 'rho')
3491 svntest.main.file_append(iota_path_backup,
3492 'My appended text for iota\n')
3493 svntest.main.file_append(lambda_path_backup,
3494 'My appended text for lambda\n')
3495 svntest.main.file_append(mu_path_backup,
3496 'My appended text for mu\n')
3497 svntest.main.file_append(alpha_path_backup,
3498 'My appended text for alpha\n')
3499 svntest.main.file_append(beta_path_backup,
3500 'My appended text for beta\n')
3501 svntest.main.file_append(pi_path_backup,
3502 'My appended text for pi\n')
3503 svntest.main.file_append(rho_path_backup,
3504 'My appended text for rho\n')
3506 # Created expected output tree for 'svn ci'
3507 expected_output = svntest.wc.State(wc_dir, {
3508 'iota' : Item(verb='Sending'),
3509 'A/B/lambda' : Item(verb='Sending'),
3510 'A/mu' : Item(verb='Sending'),
3511 'A/B/E/alpha': Item(verb='Sending'),
3512 'A/B/E/beta': Item(verb='Sending'),
3513 'A/D/G/pi' : Item(verb='Sending'),
3514 'A/D/G/rho' : Item(verb='Sending'),
3517 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
3518 expected_status.tweak('iota', wc_rev=2)
3519 expected_status.tweak('A/B/lambda', wc_rev=2)
3520 expected_status.tweak('A/mu', wc_rev=2)
3521 expected_status.tweak('A/B/E/alpha', wc_rev=2)
3522 expected_status.tweak('A/B/E/beta', wc_rev=2)
3523 expected_status.tweak('A/D/G/pi', wc_rev=2)
3524 expected_status.tweak('A/D/G/rho', wc_rev=2)
3526 # Commit.
3527 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
3528 expected_status, None, wc_dir)
3530 # Now we'll update each of our 5 files in wc_backup; each one will get
3531 # conflicts, and we'll handle each with a different --accept option.
3533 # Setup SVN_EDITOR and SVN_MERGE for --accept={edit,launch}.
3534 svntest.main.use_editor('append_foo')
3536 # iota: no accept option
3537 # Just leave the conflicts alone, since run_and_verify_svn already uses
3538 # the --non-interactive option.
3539 svntest.actions.run_and_verify_svn(None,
3540 ['C %s\n' % (iota_path_backup,),
3541 'Updated to revision 2.\n'],
3543 'update', iota_path_backup)
3545 # lambda: --accept=postpone
3546 # Just leave the conflicts alone.
3547 svntest.actions.run_and_verify_svn(None,
3548 ['C %s\n' % (lambda_path_backup,),
3549 'Updated to revision 2.\n'],
3551 'update', '--accept=postpone',
3552 lambda_path_backup)
3554 # mu: --accept=base
3555 # Accept the pre-update base file.
3556 svntest.actions.run_and_verify_svn(None,
3557 ['G %s\n' % (mu_path_backup,),
3558 'Updated to revision 2.\n'],
3560 'update', '--accept=base',
3561 mu_path_backup)
3563 # alpha: --accept=mine
3564 # Accept the user's working file.
3565 svntest.actions.run_and_verify_svn(None,
3566 ['G %s\n' % (alpha_path_backup,),
3567 'Updated to revision 2.\n'],
3569 'update', '--accept=mine',
3570 alpha_path_backup)
3572 # beta: --accept=theirs
3573 # Accept their file.
3574 svntest.actions.run_and_verify_svn(None,
3575 ['G %s\n' % (beta_path_backup,),
3576 'Updated to revision 2.\n'],
3578 'update', '--accept=theirs',
3579 beta_path_backup)
3581 # pi: --accept=edit
3582 # Run editor and accept the edited file.
3583 svntest.actions.run_and_verify_svn(None,
3584 ['G %s\n' % (pi_path_backup,),
3585 'Updated to revision 2.\n'],
3587 'update', '--accept=edit',
3588 pi_path_backup)
3590 # rho: --accept=launch
3591 # Run SVN_MERGE and accept the merged file.
3592 svntest.actions.run_and_verify_svn(None,
3593 ['G %s\n' % (rho_path_backup,),
3594 'Updated to revision 2.\n'],
3596 'update', '--accept=launch',
3597 rho_path_backup)
3599 # Set the expected disk contents for the test
3600 expected_disk = svntest.main.greek_state.copy()
3602 expected_disk.tweak('iota', contents=("This is the file 'iota'.\n"
3603 '<<<<<<< .mine\n'
3604 'My appended text for iota\n'
3605 '=======\n'
3606 'Their appended text for iota\n'
3607 '>>>>>>> .r2\n'))
3608 expected_disk.tweak('A/B/lambda', contents=("This is the file 'lambda'.\n"
3609 '<<<<<<< .mine\n'
3610 'My appended text for lambda\n'
3611 '=======\n'
3612 'Their appended text for lambda\n'
3613 '>>>>>>> .r2\n'))
3614 expected_disk.tweak('A/mu', contents="This is the file 'mu'.\n")
3615 expected_disk.tweak('A/B/E/alpha', contents=("This is the file 'alpha'.\n"
3616 'My appended text for alpha\n'))
3617 expected_disk.tweak('A/B/E/beta', contents=("This is the file 'beta'.\n"
3618 'Their appended text for beta\n'))
3619 expected_disk.tweak('A/D/G/pi', contents=("This is the file 'pi'.\n"
3620 '<<<<<<< .mine\n'
3621 'My appended text for pi\n'
3622 '=======\n'
3623 'Their appended text for pi\n'
3624 '>>>>>>> .r2\n'
3625 'foo\n'))
3626 expected_disk.tweak('A/D/G/rho', contents=("This is the file 'rho'.\n"
3627 '<<<<<<< .mine\n'
3628 'My appended text for rho\n'
3629 '=======\n'
3630 'Their appended text for rho\n'
3631 '>>>>>>> .r2\n'
3632 'foo\n'))
3634 # Set the expected extra files for the test
3635 extra_files = ['iota.*\.r1', 'iota.*\.r2', 'iota.*\.mine',
3636 'lambda.*\.r1', 'lambda.*\.r2', 'lambda.*\.mine']
3638 # Set the expected status for the test
3639 expected_status = svntest.actions.get_virginal_state(wc_backup, 2)
3640 expected_status.tweak('iota', 'A/B/lambda', 'A/mu',
3641 'A/B/E/alpha', 'A/B/E/beta',
3642 'A/D/G/pi', 'A/D/G/rho', wc_rev=2)
3643 expected_status.tweak('iota', status='C ')
3644 expected_status.tweak('A/B/lambda', status='C ')
3645 expected_status.tweak('A/mu', status='M ')
3646 expected_status.tweak('A/B/E/alpha', status='M ')
3647 expected_status.tweak('A/B/E/beta', status=' ')
3648 expected_status.tweak('A/D/G/pi', status='M ')
3649 expected_status.tweak('A/D/G/rho', status='M ')
3651 # Set the expected output for the test
3652 expected_output = wc.State(wc_backup, {})
3654 # Do the update and check the results in three ways.
3655 svntest.actions.run_and_verify_update(wc_backup,
3656 expected_output,
3657 expected_disk,
3658 expected_status,
3659 None,
3660 svntest.tree.detect_conflict_files,
3661 extra_files)
3663 # Test for a wc corruption race condition (possibly introduced in
3664 # r23342) which is easy to trigger if interactive conflict resolution
3665 # dies in the middle of prompting. Specifically, we run an update
3666 # with interactive-conflicts on but close stdin immediately, so the
3667 # prompt errors out; then the dir_baton pool cleanup handlers in the
3668 # WC update editor flush and run incomplete logs and lead to WC
3669 # corruption, detectable by another update command.
3671 def eof_in_interactive_conflict_resolver(sbox):
3672 "eof in interactive resolution can't break wc"
3674 sbox.build()
3675 wc_dir = sbox.wc_dir
3677 # Set up a custom config directory which *doesn't* turn off
3678 # interactive resolution
3679 config_contents = '''\
3680 [miscellany]
3681 interactive-conflicts = true
3683 tmp_dir = os.path.abspath(svntest.main.temp_dir)
3684 config_dir = os.path.join(tmp_dir, 'interactive-conflicts-config')
3685 svntest.main.create_config_dir(config_dir, config_contents)
3687 iota_path = os.path.join(wc_dir, 'iota')
3689 # Modify iota and commit for r2.
3690 svntest.main.file_append(iota_path, "Appended text in r2.\n")
3691 expected_output = svntest.wc.State(wc_dir, {
3692 'iota': Item(verb="Sending"),
3694 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
3695 expected_status.tweak('iota', wc_rev=2)
3696 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
3697 expected_status, None, wc_dir)
3699 # Go back to revision 1.
3700 expected_output = svntest.wc.State(wc_dir, {
3701 'iota' : Item(status='U '),
3703 expected_disk = svntest.main.greek_state.copy()
3704 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
3705 svntest.actions.run_and_verify_update(wc_dir,
3706 expected_output,
3707 expected_disk,
3708 expected_status,
3709 None,
3710 None, None,
3711 None, None, 1,
3712 '-r1', wc_dir)
3714 # Modify iota differently and try to update *with the interactive
3715 # resolver*. ### The parser won't go so well with the output
3716 svntest.main.file_append(iota_path, "Local mods to r1 text.\n")
3717 svntest.actions.run_and_verify_update(wc_dir, None, None, None,
3718 "Can't read stdin: End of file found",
3719 None, None, None, None, 1,
3720 wc_dir, '--config-dir', config_dir)
3722 # Now update -r1 again. Hopefully we don't get a checksum error!
3723 expected_output = svntest.wc.State(wc_dir, {})
3724 # note: it's possible that the correct disk here should be the
3725 # merged file?
3726 expected_disk.tweak('iota', contents=("This is the file 'iota'.\n"
3727 "Local mods to r1 text.\n"))
3728 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
3729 expected_status.tweak('iota', status='M ')
3730 svntest.actions.run_and_verify_update(wc_dir,
3731 expected_output,
3732 expected_disk,
3733 expected_status,
3734 None,
3735 None, None,
3736 None, None, 1,
3737 '-r1', wc_dir)
3741 #######################################################################
3742 # Run the tests
3745 # list all tests here, starting with None:
3746 test_list = [ None,
3747 update_binary_file,
3748 update_binary_file_2,
3749 update_ignores_added,
3750 update_to_rev_zero,
3751 receive_overlapping_same_change,
3752 update_to_resolve_text_conflicts,
3753 update_delete_modified_files,
3754 update_after_add_rm_deleted,
3755 update_missing,
3756 update_replace_dir,
3757 update_single_file,
3758 prop_update_on_scheduled_delete,
3759 update_receive_illegal_name,
3760 update_deleted_missing_dir,
3761 another_hudson_problem,
3762 update_deleted_targets,
3763 new_dir_with_spaces,
3764 non_recursive_update,
3765 checkout_empty_dir,
3766 update_to_deletion,
3767 update_deletion_inside_out,
3768 update_schedule_add_dir,
3769 update_to_future_add,
3770 nested_in_read_only,
3771 obstructed_update_alters_wc_props,
3772 update_xml_unsafe_dir,
3773 conflict_markers_matching_eol,
3774 update_eolstyle_handling,
3775 update_copy_of_old_rev,
3776 forced_update,
3777 forced_update_failures,
3778 XFail(update_wc_on_windows_drive),
3779 update_wc_with_replaced_file,
3780 update_with_obstructing_additions,
3781 update_conflicted,
3782 mergeinfo_update_elision,
3783 SkipUnless(update_handles_copyfrom,
3784 server_sends_copyfrom_on_update),
3785 copyfrom_degrades_gracefully,
3786 SkipUnless(update_handles_copyfrom_with_txdeltas,
3787 server_sends_copyfrom_on_update),
3788 update_copied_from_replaced_and_changed,
3789 update_accept_conflicts,
3790 eof_in_interactive_conflict_resolver,
3793 if __name__ == '__main__':
3794 svntest.main.run_tests(test_list)
3795 # NOTREACHED
3798 ### End of file.