In the command-line client, forbid
[svn.git] / subversion / tests / cmdline / externals_tests.py
blobc50f73ff1b23717556986ef2175c144ea406ab60
1 #!/usr/bin/env python
3 # module_tests.py: testing modules / external sources.
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 os
21 import warnings
23 # Our testing module
24 import svntest
26 # (abbreviation)
27 Skip = svntest.testcase.Skip
28 XFail = svntest.testcase.XFail
29 Item = svntest.wc.StateItem
32 ######################################################################
33 # Tests
35 # Each test must return on success or raise on failure.
38 #----------------------------------------------------------------------
40 ### todo: it's inefficient to keep calling externals_test_setup() for
41 ### every test. It's slow. But it's very safe -- we're guaranteed to
42 ### have a clean repository, built from the latest Subversion, with
43 ### the svn:externals properties preset in a known way. Right now I
44 ### can't think of any other way to achieve that guarantee, so the
45 ### result is that each individual test is slow.
47 def externals_test_setup(sbox):
48 """Set up a repository in which some directories have the externals property,
49 and set up another repository, referred to by some of those externals.
50 Both repositories contain greek trees with five revisions worth of
51 random changes, then in the sixth revision the first repository --
52 and only the first -- has some externals properties set. ### Later,
53 test putting externals on the second repository. ###
55 The arrangement of the externals in the first repository is:
57 /A/C/ ==> exdir_G <scheme>:///<other_repos>/A/D/G
58 ../../../<other_repos_basename>/A/D/H -r 1 exdir_H
60 /A/D/ ==> ^/../<other_repos_basename>/A exdir_A
61 //<other_repos>/A/D/G/ exdir_A/G/
62 exdir_A/H -r 1 <scheme>:///<other_repos>/A/D/H
63 /<some_paths>/A/B x/y/z/blah
65 A dictionary is returned keyed by the directory created by the
66 external whose value is the URL of the external.
67 """
69 # The test itself will create a working copy
70 sbox.build(create_wc = False)
72 svntest.main.safe_rmtree(sbox.wc_dir)
74 wc_init_dir = sbox.add_wc_path('init') # just for setting up props
75 repo_dir = sbox.repo_dir
76 repo_url = sbox.repo_url
77 other_repo_dir, other_repo_url = sbox.add_repo_path('other')
78 other_repo_basename = os.path.basename(other_repo_dir)
80 # Get a scheme relative URL to the other repository.
81 scheme_relative_other_repo_url = other_repo_url[other_repo_url.find(':')+1:]
83 # Get a server root relative URL to the other repository by trimming
84 # off the first three /'s.
85 server_relative_other_repo_url = other_repo_url
86 for i in range(3):
87 j = server_relative_other_repo_url.find('/') + 1
88 server_relative_other_repo_url = server_relative_other_repo_url[j:]
89 server_relative_other_repo_url = '/' + server_relative_other_repo_url
91 # These files will get changed in revisions 2 through 5.
92 mu_path = os.path.join(wc_init_dir, "A/mu")
93 pi_path = os.path.join(wc_init_dir, "A/D/G/pi")
94 lambda_path = os.path.join(wc_init_dir, "A/B/lambda")
95 omega_path = os.path.join(wc_init_dir, "A/D/H/omega")
97 # These are the directories on which `svn:externals' will be set, in
98 # revision 6 on the first repo.
99 C_path = os.path.join(wc_init_dir, "A/C")
100 D_path = os.path.join(wc_init_dir, "A/D")
102 # Create a working copy.
103 svntest.actions.run_and_verify_svn(None, None, [],
104 'checkout',
105 repo_url, wc_init_dir)
107 # Make revisions 2 through 5, but don't bother with pre- and
108 # post-commit status checks.
110 svntest.main.file_append(mu_path, "Added to mu in revision 2.\n")
111 svntest.actions.run_and_verify_svn(None, None, [],
112 'ci', '-m', 'log msg',
113 '--quiet', wc_init_dir)
115 svntest.main.file_append(pi_path, "Added to pi in revision 3.\n")
116 svntest.actions.run_and_verify_svn(None, None, [],
117 'ci', '-m', 'log msg',
118 '--quiet', wc_init_dir)
120 svntest.main.file_append(lambda_path, "Added to lambda in revision 4.\n")
121 svntest.actions.run_and_verify_svn(None, None, [],
122 'ci', '-m', 'log msg',
123 '--quiet', wc_init_dir)
125 svntest.main.file_append(omega_path, "Added to omega in revision 5.\n")
126 svntest.actions.run_and_verify_svn(None, None, [],
127 'ci', '-m', 'log msg',
128 '--quiet', wc_init_dir)
130 # Get the whole working copy to revision 5.
131 svntest.actions.run_and_verify_svn(None, None, [],
132 'up', wc_init_dir)
134 # Now copy the initial repository to create the "other" repository,
135 # the one to which the first repository's `svn:externals' properties
136 # will refer. After this, both repositories have five revisions
137 # of random stuff, with no svn:externals props set yet.
138 svntest.main.copy_repos(repo_dir, other_repo_dir, 5)
140 # This is the returned dictionary.
141 external_url_for = { }
143 external_url_for["A/C/exdir_G"] = other_repo_url + "/A/D/G"
144 external_url_for["A/C/exdir_H"] = "../../../" + \
145 other_repo_basename + \
146 "/A/D/H"
148 # Set up the externals properties on A/B/ and A/D/.
149 externals_desc = \
150 "exdir_G " + external_url_for["A/C/exdir_G"] + "\n" + \
151 external_url_for["A/C/exdir_H"] + " -r 1 exdir_H\n"
153 tmp_f = os.tempnam(wc_init_dir, 'tmp')
154 svntest.main.file_append(tmp_f, externals_desc)
155 svntest.actions.run_and_verify_svn(None, None, [],
156 'pset',
157 '-F', tmp_f, 'svn:externals', C_path)
159 os.remove(tmp_f)
161 external_url_for["A/D/exdir_A"] = "^/../" + other_repo_basename + "/A"
162 external_url_for["A/D/exdir_A/G/"] = scheme_relative_other_repo_url + \
163 "/A/D/G/"
164 external_url_for["A/D/exdir_A/H"] = other_repo_url + "/A/D/H"
165 external_url_for["A/D/x/y/z/blah"] = server_relative_other_repo_url + "/A/B"
167 externals_desc = \
168 external_url_for["A/D/exdir_A"] + " exdir_A" + \
169 "\n" + \
170 external_url_for["A/D/exdir_A/G/"] + " exdir_A/G/" + \
171 "\n" + \
172 "exdir_A/H -r 1 " + external_url_for["A/D/exdir_A/H"] + \
173 "\n" + \
174 external_url_for["A/D/x/y/z/blah"] + " x/y/z/blah" + \
175 "\n"
177 svntest.main.file_append(tmp_f, externals_desc)
178 svntest.actions.run_and_verify_svn(None, None, [], 'pset',
179 '-F', tmp_f, 'svn:externals', D_path)
181 os.remove(tmp_f)
183 # Commit the property changes.
185 expected_output = svntest.wc.State(wc_init_dir, {
186 'A/C' : Item(verb='Sending'),
187 'A/D' : Item(verb='Sending'),
190 expected_status = svntest.actions.get_virginal_state(wc_init_dir, 5)
191 expected_status.tweak('A/C', 'A/D', wc_rev=6, status=' ')
193 svntest.actions.run_and_verify_commit(wc_init_dir,
194 expected_output,
195 expected_status,
196 None, None, None, None, None,
197 wc_init_dir)
199 return external_url_for
201 def change_external(path, new_val):
202 """Change the value of the externals property on PATH to NEW_VAL,
203 and commit the change."""
204 tmp_f = os.tempnam(svntest.main.temp_dir, 'tmp')
205 svntest.main.file_append(tmp_f, new_val)
206 svntest.actions.run_and_verify_svn(None, None, [], 'pset',
207 '-F', tmp_f, 'svn:externals', path)
208 svntest.actions.run_and_verify_svn(None, None, [], 'ci',
209 '-m', 'log msg', '--quiet', path)
210 os.remove(tmp_f)
213 def probe_paths_exist(paths):
214 """ Probe each one of PATHS to see if it exists, otherwise throw a
215 Failure exception. """
217 for path in paths:
218 if not os.path.exists(path):
219 raise svntest.Failure("Probing for " + path + " failed.")
222 def probe_paths_missing(paths):
223 """ Probe each one of PATHS to see if does not exist, otherwise throw a
224 Failure exception. """
226 for path in paths:
227 if os.path.exists(path):
228 raise svntest.Failure(path + " unexpectedly still exists.")
231 #----------------------------------------------------------------------
234 ### todo: It would be great if everything used the new wc.py system to
235 ### check output/status. In fact, it would be great to do more output
236 ### and status checking period! But must first see how well the
237 ### output checkers deal with multiple summary lines. With external
238 ### modules, you can get the first "Updated to revision X" line, and
239 ### then there will be more "Updated to..." and "Checked out..." lines
240 ### following it, one line for each new or changed external.
243 #----------------------------------------------------------------------
245 def checkout_with_externals(sbox):
246 "test checkouts with externals"
248 externals_test_setup(sbox)
250 wc_dir = sbox.wc_dir
251 repo_url = sbox.repo_url
253 # Create a working copy.
254 svntest.actions.run_and_verify_svn(None, None, [],
255 'checkout',
256 repo_url, wc_dir)
258 # Probe the working copy a bit, see if it's as expected.
259 expected_existing_paths = [
260 os.path.join(wc_dir, "A", "C", "exdir_G"),
261 os.path.join(wc_dir, "A", "C", "exdir_G", "pi"),
262 os.path.join(wc_dir, "A", "C", "exdir_H"),
263 os.path.join(wc_dir, "A", "C", "exdir_H", "omega"),
264 os.path.join(wc_dir, "A", "D", "x"),
265 os.path.join(wc_dir, "A", "D", "x", "y"),
266 os.path.join(wc_dir, "A", "D", "x", "y", "z"),
267 os.path.join(wc_dir, "A", "D", "x", "y", "z", "blah"),
268 os.path.join(wc_dir, "A", "D", "x", "y", "z", "blah", "E", "alpha"),
269 os.path.join(wc_dir, "A", "D", "x", "y", "z", "blah", "E", "beta"),
271 probe_paths_exist(expected_existing_paths)
273 # Pick a file at random, make sure it has the expected contents.
274 exdir_H_omega_path = os.path.join(wc_dir, "A", "C", "exdir_H", "omega")
275 fp = open(exdir_H_omega_path, 'r')
276 lines = fp.readlines()
277 if not ((len(lines) == 1) and (lines[0] == "This is the file 'omega'.\n")):
278 raise svntest.Failure("Unexpected contents for rev 1 of " +
279 exdir_H_omega_path)
281 #----------------------------------------------------------------------
283 def update_receive_new_external(sbox):
284 "update to receive a new external module"
286 external_url_for = externals_test_setup(sbox)
287 wc_dir = sbox.wc_dir
289 other_wc_dir = sbox.add_wc_path('other')
290 repo_url = sbox.repo_url
291 other_repo_url = repo_url + ".other"
293 # Checkout two working copies.
294 svntest.actions.run_and_verify_svn(None, None, [],
295 'checkout',
296 repo_url, wc_dir)
298 svntest.actions.run_and_verify_svn(None, None, [],
299 'checkout',
300 repo_url, other_wc_dir)
302 # Add one new external item to the property on A/D. The new item is
303 # "exdir_E", deliberately added in the middle not at the end.
304 new_externals_desc = \
305 external_url_for["A/D/exdir_A"] + " exdir_A" + \
306 "\n" + \
307 external_url_for["A/D/exdir_A/G/"] + " exdir_A/G/" + \
308 "\n" + \
309 "exdir_E " + other_repo_url + "/A/B/E" + \
310 "\n" + \
311 "exdir_A/H -r 1 " + external_url_for["A/D/exdir_A/H"] + \
312 "\n" + \
313 external_url_for["A/D/x/y/z/blah"] + " x/y/z/blah" + \
314 "\n"
316 # Set and commit the property
317 change_external(os.path.join(wc_dir, "A/D"), new_externals_desc)
319 # Update the other working copy, see if we get the new item.
320 svntest.actions.run_and_verify_svn(None, None, [], 'up', other_wc_dir)
322 probe_paths_exist([os.path.join(other_wc_dir, "A", "D", "exdir_E")])
324 #----------------------------------------------------------------------
326 def update_lose_external(sbox):
327 "update to lose an external module"
329 external_url_for = externals_test_setup(sbox)
330 wc_dir = sbox.wc_dir
332 other_wc_dir = sbox.add_wc_path('other')
333 repo_url = sbox.repo_url
335 # Checkout two working copies.
336 svntest.actions.run_and_verify_svn(None, None, [],
337 'checkout',
338 repo_url, wc_dir)
340 svntest.actions.run_and_verify_svn(None, None, [],
341 'checkout',
342 repo_url, other_wc_dir)
344 # Lose one new external item from A/D. The lost item is
345 # "exdir_A", chosen because there are two other externals underneath
346 # it (G and H) which are not being removed. We expect them to
347 # remain -- in other words:
349 # BEFORE AFTER
350 # ------------ ------------
351 # A/D/exdir_A A/D/exdir_A
352 # A/D/exdir_A/.svn/... <GONE>
353 # A/D/exdir_A/mu <GONE>
354 # A/D/exdir_A/B/... <GONE>
355 # A/D/exdir_A/C/... <GONE>
356 # A/D/exdir_A/D/... <GONE>
357 # A/D/exdir_A/G/... A/D/exdir_A/G/...
358 # A/D/exdir_A/H/... A/D/exdir_A/H/...
360 new_externals_desc = \
361 external_url_for["A/D/exdir_A/G/"] + " exdir_A/G" + \
362 "\n" + \
363 "exdir_A/H -r 1 " + external_url_for["A/D/exdir_A/H"] + \
364 "\n" + \
365 external_url_for["A/D/x/y/z/blah"] + " x/y/z/blah" + \
366 "\n"
368 # Set and commit the property
369 change_external(os.path.join(wc_dir, "A/D"), new_externals_desc)
371 # Update other working copy, see if lose & preserve things appropriately
372 svntest.actions.run_and_verify_svn(None, None, [], 'up', other_wc_dir)
374 expected_existing_paths = [
375 os.path.join(other_wc_dir, "A", "D", "exdir_A"),
376 os.path.join(other_wc_dir, "A", "D", "exdir_A", "G"),
377 os.path.join(other_wc_dir, "A", "D", "exdir_A", "H"),
379 probe_paths_exist(expected_existing_paths)
381 expected_missing_paths = [
382 os.path.join(other_wc_dir, "A", "D", "exdir_A", "mu"),
383 os.path.join(other_wc_dir, "A", "D", "exdir_A", "B"),
384 os.path.join(other_wc_dir, "A", "D", "exdir_A", "C"),
385 os.path.join(other_wc_dir, "A", "D", "exdir_A", "D"),
387 probe_paths_missing(expected_missing_paths)
389 #----------------------------------------------------------------------
391 def update_change_pristine_external(sbox):
392 "update change to an unmodified external module"
394 external_url_for = externals_test_setup(sbox)
395 wc_dir = sbox.wc_dir
397 other_wc_dir = sbox.add_wc_path('other')
398 repo_url = sbox.repo_url
399 other_repo_url = repo_url + ".other"
401 # Checkout two working copies.
402 svntest.actions.run_and_verify_svn(None, None, [],
403 'checkout',
404 repo_url, wc_dir)
406 svntest.actions.run_and_verify_svn(None, None, [],
407 'checkout',
408 repo_url, other_wc_dir)
410 # Change the "x/y/z/blah" external on A/D to point to a different
411 # URL. Since no changes were made to the old checked-out external,
412 # we should get a clean replace.
413 new_externals_desc = \
414 external_url_for["A/D/exdir_A"] + " exdir_A" + \
415 "\n" + \
416 external_url_for["A/D/exdir_A/G/"] + " exdir_A/G" + \
417 "\n" + \
418 "exdir_A/H -r 1 " + external_url_for["A/D/exdir_A/H"] + \
419 "\n" + \
420 "x/y/z/blah " + other_repo_url + "/A/B/F" + \
421 "\n"
423 # Set and commit the property
424 change_external(os.path.join(wc_dir, "A/D"), new_externals_desc)
426 # Update other working copy, see if get the right change.
427 svntest.actions.run_and_verify_svn(None, None, [], 'up', other_wc_dir)
429 xyzb_path = os.path.join(other_wc_dir, "x", "y", "z", "blah")
431 expected_missing_paths = [
432 os.path.join(xyzb_path, "alpha"),
433 os.path.join(xyzb_path, "beta"),
435 probe_paths_missing(expected_missing_paths)
437 def update_change_modified_external(sbox):
438 "update changes to a modified external module"
440 external_url_for = externals_test_setup(sbox)
441 wc_dir = sbox.wc_dir
443 other_wc_dir = sbox.add_wc_path('other')
444 repo_url = sbox.repo_url
445 other_repo_url = repo_url + ".other"
447 # Checkout two working copies.
448 svntest.actions.run_and_verify_svn(None, None, [],
449 'checkout',
450 repo_url, wc_dir)
452 svntest.actions.run_and_verify_svn(None, None, [],
453 'checkout',
454 repo_url, other_wc_dir)
456 # Make a couple of mods in the "x/y/z/blah/" external.
457 alpha_path = os.path.join(other_wc_dir, "A", "D",
458 "x", "y", "z", "blah", "alpha")
459 svntest.main.file_append(alpha_path, "Some new text in alpha.\n")
460 new_file = os.path.join(other_wc_dir, "A", "D",
461 "x", "y", "z", "blah", "fish.txt")
462 svntest.main.file_append(new_file, "This is an unversioned file.\n")
464 # Change the "x/y/z/blah" external on A/D to point to a different
465 # URL. There are some local mods under the old checked-out external,
466 # so the old dir should be saved under a new name.
467 new_externals_desc = \
468 external_url_for["A/D/exdir_A"] + " exdir_A" + \
469 "\n" + \
470 external_url_for["A/D/exdir_A/G/"] + " exdir_A/G/" + \
471 "\n" + \
472 "exdir_A/H -r 1 " + external_url_for["A/D/exdir_A/H"] + \
473 "\n" + \
474 "x/y/z/blah " + other_repo_url + "/A/B/F" + \
475 "\n"
477 # Set and commit the property
478 change_external(os.path.join(wc_dir, "A/D"), new_externals_desc)
480 # Update other working copy, see if get the right change.
481 svntest.actions.run_and_verify_svn(None, None, [], 'up', other_wc_dir)
483 xyzb_path = os.path.join(other_wc_dir, "x", "y", "z", "blah")
485 expected_missing_paths = [
486 os.path.join(xyzb_path, "alpha"),
487 os.path.join(xyzb_path, "beta"),
489 probe_paths_missing(expected_missing_paths)
491 def update_receive_change_under_external(sbox):
492 "update changes under an external module"
494 externals_test_setup(sbox)
495 wc_dir = sbox.wc_dir
497 other_wc_dir = sbox.add_wc_path('other')
498 repo_url = sbox.repo_url
499 other_repo_url = repo_url + ".other"
501 # Checkout two working copies.
502 svntest.actions.run_and_verify_svn(None, None, [],
503 'checkout',
504 repo_url, wc_dir)
506 svntest.actions.run_and_verify_svn(None, None, [],
507 'checkout',
508 other_repo_url, other_wc_dir)
510 # Commit some modifications from the other_wc.
511 other_gamma_path = os.path.join(other_wc_dir, 'A', 'D', 'gamma')
512 svntest.main.file_append(other_gamma_path, "New text in other gamma.\n")
514 expected_output = svntest.wc.State(other_wc_dir, {
515 'A/D/gamma' : Item(verb='Sending'),
517 expected_status = svntest.actions.get_virginal_state(other_wc_dir, 5)
518 expected_status.tweak('A/D/gamma', wc_rev=6)
519 svntest.actions.run_and_verify_commit(other_wc_dir,
520 expected_output,
521 expected_status,
522 None, None, None, None, None,
523 other_wc_dir)
525 # Now update the regular wc to see if we get the change. Note that
526 # none of the module *properties* in this wc have been changed; only
527 # the source repository of the modules has received a change, and
528 # we're verifying that an update here pulls that change.
530 # The output's going to be all screwy because of the module
531 # notifications, so don't bother parsing it, just run update
532 # directly.
533 svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
535 external_gamma_path = os.path.join(wc_dir, 'A', 'D', 'exdir_A', 'D', 'gamma')
536 fp = open(external_gamma_path, 'r')
537 lines = fp.readlines()
538 if not ((len(lines) == 2)
539 and (lines[0] == "This is the file 'gamma'.\n")
540 and (lines[1] == "New text in other gamma.\n")):
541 raise svntest.Failure("Unexpected contents for externally modified " +
542 external_gamma_path)
543 fp.close()
545 # Commit more modifications
546 other_rho_path = os.path.join(other_wc_dir, 'A', 'D', 'G', 'rho')
547 svntest.main.file_append(other_rho_path, "New text in other rho.\n")
549 expected_output = svntest.wc.State(other_wc_dir, {
550 'A/D/G/rho' : Item(verb='Sending'),
552 expected_status = svntest.actions.get_virginal_state(other_wc_dir, 5)
553 expected_status.tweak('A/D/gamma', wc_rev=6)
554 expected_status.tweak('A/D/G/rho', wc_rev=7)
555 svntest.actions.run_and_verify_commit(other_wc_dir,
556 expected_output,
557 expected_status,
558 None, None, None, None, None,
559 other_wc_dir)
561 svntest.actions.run_and_verify_svn(None, None, [],
562 'up', os.path.join(wc_dir, "A", "C"))
564 external_rho_path = os.path.join(wc_dir, 'A', 'C', 'exdir_G', 'rho')
565 fp = open(external_rho_path, 'r')
566 lines = fp.readlines()
567 if not ((len(lines) == 2)
568 and (lines[0] == "This is the file 'rho'.\n")
569 and (lines[1] == "New text in other rho.\n")):
570 raise svntest.Failure("Unexpected contents for externally modified " +
571 external_rho_path)
572 fp.close()
574 #----------------------------------------------------------------------
576 def modify_and_update_receive_new_external(sbox):
577 "commit and update additional externals"
579 external_url_for = externals_test_setup(sbox)
580 wc_dir = sbox.wc_dir
581 repo_url = sbox.repo_url
583 # Checkout a working copy
584 svntest.actions.run_and_verify_svn(None, None, [],
585 'checkout',
586 repo_url, wc_dir)
588 # Add one more external item
589 B_path = os.path.join(wc_dir, "A/B")
590 externals_desc = \
591 external_url_for["A/D/exdir_A/G/"] + " exdir_G" + \
592 "\n" + \
593 "exdir_H -r 1 " + external_url_for["A/D/exdir_A/H"] + \
594 "\n" + \
595 "exdir_Z " + external_url_for["A/D/exdir_A/H"] + \
596 "\n"
598 tmp_f = os.tempnam()
599 svntest.main.file_append(tmp_f, externals_desc)
600 svntest.actions.run_and_verify_svn(None, None, [],
601 'pset', '-F', tmp_f,
602 'svn:externals', B_path)
603 os.remove(tmp_f)
605 # Now cd into A/B and try updating
606 was_cwd = os.getcwd()
607 os.chdir(B_path)
609 # Once upon a time there was a core-dump here
611 svntest.actions.run_and_verify_svn("update failed",
612 svntest.verify.AnyOutput, [], 'up' )
614 os.chdir(was_cwd)
616 probe_paths_exist([os.path.join(B_path, "exdir_Z")])
618 #----------------------------------------------------------------------
620 def disallow_dot_or_dotdot_directory_reference(sbox):
621 "error if external target dir involves '.' or '..'"
623 external_url_for = externals_test_setup(sbox)
624 wc_dir = sbox.wc_dir
626 # Try to set illegal externals in the original WC.
627 def set_externals_for_path_expect_error(path, val):
628 tmp_f = os.tempnam()
629 svntest.main.file_append(tmp_f, val)
630 svntest.actions.run_and_verify_svn(None, None, svntest.verify.AnyOutput,
631 'pset', '-F', tmp_f,
632 'svn:externals', path)
633 os.remove(tmp_f)
635 B_path = os.path.join(wc_dir, 'A', 'B')
636 G_path = os.path.join(wc_dir, 'A', 'D', 'G')
637 H_path = os.path.join(wc_dir, 'A', 'D', 'H')
638 C_path = os.path.join(wc_dir, 'A', 'C')
639 F_path = os.path.join(wc_dir, 'A', 'C', 'F')
641 external_urls = external_url_for.values()
643 externals_value_1 = "../foo" + " " + external_urls.pop() + "\n"
644 if not external_urls: external_urls = external_url_for.values()
645 externals_value_2 = "foo/bar/../baz" + " " + external_urls.pop() + "\n"
646 if not external_urls: external_urls = external_url_for.values()
647 externals_value_3 = "foo/.." + " " + external_urls.pop() + "\n"
648 if not external_urls: external_urls = external_url_for.values()
649 externals_value_4 = "." + " " + external_urls.pop() + "\n"
650 if not external_urls: external_urls = external_url_for.values()
651 externals_value_5 = "./" + " " + external_urls.pop() + "\n"
652 if not external_urls: external_urls = external_url_for.values()
653 externals_value_6 = ".." + " " + external_urls.pop() + "\n"
654 if not external_urls: external_urls = external_url_for.values()
655 externals_value_7 = "././/.///." + " " + external_urls.pop() + "\n"
656 if not external_urls: external_urls = external_url_for.values()
657 externals_value_8 = "/foo" + " " + external_urls.pop() + "\n"
658 if not external_urls: external_urls = external_url_for.values()
660 set_externals_for_path_expect_error(B_path, externals_value_1)
661 set_externals_for_path_expect_error(G_path, externals_value_2)
662 set_externals_for_path_expect_error(H_path, externals_value_3)
663 set_externals_for_path_expect_error(C_path, externals_value_4)
664 set_externals_for_path_expect_error(F_path, externals_value_5)
665 set_externals_for_path_expect_error(B_path, externals_value_6)
666 set_externals_for_path_expect_error(G_path, externals_value_7)
667 set_externals_for_path_expect_error(H_path, externals_value_8)
670 #----------------------------------------------------------------------
672 def export_with_externals(sbox):
673 "test exports with externals"
675 externals_test_setup(sbox)
677 wc_dir = sbox.wc_dir
678 repo_url = sbox.repo_url
680 # Create a working copy.
681 svntest.actions.run_and_verify_svn(None, None, [],
682 'export',
683 repo_url, wc_dir)
685 # Probe the working copy a bit, see if it's as expected.
686 expected_existing_paths = [
687 os.path.join(wc_dir, "A", "C", "exdir_G"),
688 os.path.join(wc_dir, "A", "C", "exdir_G", "pi"),
689 os.path.join(wc_dir, "A", "C", "exdir_H"),
690 os.path.join(wc_dir, "A", "C", "exdir_H", "omega"),
691 os.path.join(wc_dir, "A", "D", "x"),
692 os.path.join(wc_dir, "A", "D", "x", "y"),
693 os.path.join(wc_dir, "A", "D", "x", "y", "z"),
694 os.path.join(wc_dir, "A", "D", "x", "y", "z", "blah"),
695 os.path.join(wc_dir, "A", "D", "x", "y", "z", "blah", "E", "alpha"),
696 os.path.join(wc_dir, "A", "D", "x", "y", "z", "blah", "E", "beta"),
698 probe_paths_exist(expected_existing_paths)
700 # Pick some files, make sure their contents are as expected.
701 exdir_G_pi_path = os.path.join(wc_dir, "A", "C", "exdir_G", "pi")
702 fp = open(exdir_G_pi_path, 'r')
703 lines = fp.readlines()
704 if not ((len(lines) == 2) \
705 and (lines[0] == "This is the file 'pi'.\n") \
706 and (lines[1] == "Added to pi in revision 3.\n")):
707 raise svntest.Failure("Unexpected contents for rev 1 of " +
708 exdir_G_pi_path)
710 exdir_H_omega_path = os.path.join(wc_dir, "A", "C", "exdir_H", "omega")
711 fp = open(exdir_H_omega_path, 'r')
712 lines = fp.readlines()
713 if not ((len(lines) == 1) and (lines[0] == "This is the file 'omega'.\n")):
714 raise svntest.Failure("Unexpected contents for rev 1 of " +
715 exdir_H_omega_path)
717 #----------------------------------------------------------------------
719 # Test for issue #2429
720 def export_wc_with_externals(sbox):
721 "test exports from working copies with externals"
723 externals_test_setup(sbox)
725 wc_dir = sbox.wc_dir
726 repo_url = sbox.repo_url
727 export_target = sbox.add_wc_path('export')
729 # Create a working copy.
730 svntest.actions.run_and_verify_svn(None, None, [],
731 'checkout',
732 repo_url, wc_dir)
733 # Export the working copy.
734 svntest.actions.run_and_verify_svn(None, None, [],
735 'export', wc_dir, export_target)
737 paths = [
738 os.path.join(export_target, "A", "C", "exdir_G"),
739 os.path.join(export_target, "A", "C", "exdir_G", "pi"),
740 os.path.join(export_target, "A", "C", "exdir_H"),
741 os.path.join(export_target, "A", "C", "exdir_H", "omega"),
742 os.path.join(export_target, "A", "D", "x"),
743 os.path.join(export_target, "A", "D", "x", "y"),
744 os.path.join(export_target, "A", "D", "x", "y", "z"),
745 os.path.join(export_target, "A", "D", "x", "y", "z", "blah"),
746 os.path.join(export_target, "A", "D", "x", "y", "z", "blah", "E", "alpha"),
747 os.path.join(export_target, "A", "D", "x", "y", "z", "blah", "E", "beta"),
749 probe_paths_exist(paths)
751 svntest.main.safe_rmtree(export_target)
753 # Export it again, without externals.
754 svntest.actions.run_and_verify_svn(None, None, [],
755 'export', '--ignore-externals',
756 wc_dir, export_target)
757 probe_paths_missing(paths)
759 #----------------------------------------------------------------------
761 def external_with_peg_and_op_revision(sbox):
762 "use a peg revision to specify an external module"
764 external_url_for = externals_test_setup(sbox)
765 wc_dir = sbox.wc_dir
766 repo_url = sbox.repo_url
768 # Checkout a working copy.
769 svntest.actions.run_and_verify_svn(None, None, [],
770 'checkout',
771 repo_url, wc_dir)
773 # remove A/D/H in the other repo
774 svntest.actions.run_and_verify_svn(None, None, [],
775 'rm',
776 external_url_for["A/D/exdir_A/H"],
777 '-m', 'remove original A/D/H')
779 # Set an external property using peg revision syntax.
780 new_externals_desc = \
781 external_url_for["A/D/exdir_A/H"] + "@4 exdir_A/H" + \
782 "\n" + \
783 external_url_for["A/D/exdir_A/G/"] + " exdir_A/G" + \
784 "\n"
786 # Set and commit the property.
787 change_external(os.path.join(wc_dir, "A/D"), new_externals_desc)
789 # Update other working copy, see if we get the right change.
790 svntest.actions.run_and_verify_svn(None, None, [],
791 'up', wc_dir)
793 external_chi_path = os.path.join(wc_dir, 'A', 'D', 'exdir_A', 'H', 'chi')
794 fp = open(external_chi_path, 'r')
795 lines = fp.readlines()
796 if not ((len(lines) == 1)
797 and (lines[0] == "This is the file 'chi'.\n")):
798 raise svntest.Failure("Unexpected contents for externally modified " +
799 external_chi_path)
800 fp.close()
802 #----------------------------------------------------------------------
804 def new_style_externals(sbox):
805 "check the new '-rN URL PATH' syntax"
807 external_url_for = externals_test_setup(sbox)
808 wc_dir = sbox.wc_dir
809 repo_url = sbox.repo_url
811 # Checkout a working copy.
812 svntest.actions.run_and_verify_svn(None, None, [],
813 'checkout',
814 repo_url, wc_dir)
816 # Set an external property using the new '-rN URL PATH' syntax.
817 new_externals_desc = \
818 external_url_for["A/C/exdir_G"] + " exdir_G" + \
819 "\n" + \
820 "-r 1 " + external_url_for["A/C/exdir_H"] + " exdir_H" + \
821 "\n" + \
822 "-r1 " + external_url_for["A/C/exdir_H"] + " exdir_I" + \
823 "\n"
825 # Set and commit the property.
826 change_external(os.path.join(wc_dir, "A/C"), new_externals_desc)
828 # Update other working copy.
829 svntest.actions.run_and_verify_svn(None, None, [],
830 'up', wc_dir)
832 for dir_name in ["exdir_H", "exdir_I"]:
833 exdir_X_omega_path = os.path.join(wc_dir, "A", "C", dir_name, "omega")
834 fp = open(exdir_X_omega_path, 'r')
835 lines = fp.readlines()
836 if not ((len(lines) == 1) and (lines[0] == "This is the file 'omega'.\n")):
837 raise svntest.Failure("Unexpected contents for rev 1 of " +
838 exdir_X_omega_path)
840 #----------------------------------------------------------------------
842 def disallow_propset_invalid_formatted_externals(sbox):
843 "error if propset'ing external with invalid format"
845 # Bootstrap
846 sbox.build()
847 wc_dir = sbox.wc_dir
849 A_path = os.path.join(wc_dir, 'A')
851 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
852 svntest.actions.run_and_verify_status(wc_dir, expected_status)
854 # It should not be possible to set these external properties on a
855 # directory.
856 for ext in [ 'arg1',
857 'arg1 arg2 arg3',
858 'arg1 arg2 arg3 arg4',
859 'arg1 arg2 arg3 arg4 arg5',
860 '-r',
861 '-r1',
862 '-r 1',
863 '-r1 arg1',
864 '-r 1 arg1',
865 'arg1 -r',
866 'arg1 -r1',
867 'arg1 -r 1',
869 tmp_f = os.tempnam()
870 svntest.main.file_append(tmp_f, ext)
871 svntest.actions.run_and_verify_svn("No error for externals '%s'" % ext,
872 None,
873 '.*Error parsing svn:externals.*',
874 'propset',
875 '-F',
876 tmp_f,
877 'svn:externals',
878 A_path)
879 os.remove(tmp_f)
881 for ext in [ '-r abc arg1 arg2',
882 '-rabc arg1 arg2',
883 'arg1 -r abc arg2',
884 'arg1 -rabc arg2',
886 tmp_f = os.tempnam()
887 svntest.main.file_append(tmp_f, ext)
888 svntest.actions.run_and_verify_svn("No error for externals '%s'" % ext,
889 None,
890 '.*Invalid revision number found.*',
891 'propset',
892 '-F',
893 tmp_f,
894 'svn:externals',
895 A_path)
896 os.remove(tmp_f)
898 #----------------------------------------------------------------------
900 def old_style_externals_ignore_peg_reg(sbox):
901 "old 'PATH URL' format should ignore peg revisions"
903 external_url_for = externals_test_setup(sbox)
904 wc_dir = sbox.wc_dir
905 repo_url = sbox.repo_url
907 # Checkout a working copy.
908 svntest.actions.run_and_verify_svn(None, None, [],
909 'checkout',
910 repo_url, wc_dir)
912 # Update the working copy.
913 svntest.actions.run_and_verify_svn(None, None, [],
914 'up', wc_dir)
916 # Set an external property using the old 'PATH URL' syntax with
917 # @HEAD in the URL.
918 ext = "exdir_G " + external_url_for["A/C/exdir_G"] + "@HEAD\n"
920 # Set and commit the property.
921 change_external(os.path.join(wc_dir, "A"), ext)
923 # Update the working copy. This should fail because the URL with
924 # '@HEAD' does not exist.
925 svntest.actions.run_and_verify_svn("External '%s' used pegs" % ext.strip(),
926 None,
927 ".*URL '.*/A/D/G@HEAD' doesn't exist",
928 'up',
929 wc_dir)
932 ########################################################################
933 # Run the tests
936 # list all tests here, starting with None:
937 test_list = [ None,
938 checkout_with_externals,
939 update_receive_new_external,
940 update_lose_external,
941 update_change_pristine_external,
942 update_change_modified_external,
943 update_receive_change_under_external,
944 modify_and_update_receive_new_external,
945 disallow_dot_or_dotdot_directory_reference,
946 export_with_externals,
947 export_wc_with_externals,
948 external_with_peg_and_op_revision,
949 new_style_externals,
950 disallow_propset_invalid_formatted_externals,
951 old_style_externals_ignore_peg_reg
954 if __name__ == '__main__':
955 warnings.filterwarnings('ignore', 'tempnam', RuntimeWarning)
956 svntest.main.run_tests(test_list)
957 # NOTREACHED
960 ### End of file.