(entries, src, dst, symlinks, ignore, copy_function,
ignore_dangling_symlinks, dirs_exist_ok=False)
| 462 | return _ignore_patterns |
| 463 | |
| 464 | def _copytree(entries, src, dst, symlinks, ignore, copy_function, |
| 465 | ignore_dangling_symlinks, dirs_exist_ok=False): |
| 466 | if ignore is not None: |
| 467 | ignored_names = ignore(os.fspath(src), [x.name for x in entries]) |
| 468 | else: |
| 469 | ignored_names = () |
| 470 | |
| 471 | os.makedirs(dst, exist_ok=dirs_exist_ok) |
| 472 | errors = [] |
| 473 | use_srcentry = copy_function is copy2 or copy_function is copy |
| 474 | |
| 475 | for srcentry in entries: |
| 476 | if srcentry.name in ignored_names: |
| 477 | continue |
| 478 | srcname = os.path.join(src, srcentry.name) |
| 479 | dstname = os.path.join(dst, srcentry.name) |
| 480 | srcobj = srcentry if use_srcentry else srcname |
| 481 | try: |
| 482 | is_symlink = srcentry.is_symlink() |
| 483 | if is_symlink and os.name == 'nt': |
| 484 | # Special check for directory junctions, which appear as |
| 485 | # symlinks but we want to recurse. |
| 486 | lstat = srcentry.stat(follow_symlinks=False) |
| 487 | if lstat.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT: |
| 488 | is_symlink = False |
| 489 | if is_symlink: |
| 490 | linkto = os.readlink(srcname) |
| 491 | if symlinks: |
| 492 | # We can't just leave it to `copy_function` because legacy |
| 493 | # code with a custom `copy_function` may rely on copytree |
| 494 | # doing the right thing. |
| 495 | os.symlink(linkto, dstname) |
| 496 | copystat(srcobj, dstname, follow_symlinks=not symlinks) |
| 497 | else: |
| 498 | # ignore dangling symlink if the flag is on |
| 499 | if not os.path.exists(linkto) and ignore_dangling_symlinks: |
| 500 | continue |
| 501 | # otherwise let the copy occur. copy2 will raise an error |
| 502 | if srcentry.is_dir(): |
| 503 | copytree(srcobj, dstname, symlinks, ignore, |
| 504 | copy_function, ignore_dangling_symlinks, |
| 505 | dirs_exist_ok) |
| 506 | else: |
| 507 | copy_function(srcobj, dstname) |
| 508 | elif srcentry.is_dir(): |
| 509 | copytree(srcobj, dstname, symlinks, ignore, copy_function, |
| 510 | ignore_dangling_symlinks, dirs_exist_ok) |
| 511 | else: |
| 512 | # Will raise a SpecialFileError for unsupported file types |
| 513 | copy_function(srcobj, dstname) |
| 514 | # catch the Error from the recursive copytree so that we can |
| 515 | # continue with other files |
| 516 | except Error as err: |
| 517 | errors.extend(err.args[0]) |
| 518 | except OSError as why: |
| 519 | errors.append((srcname, dstname, str(why))) |
| 520 | try: |
| 521 | copystat(src, dst) |
no test coverage detected