fileutils.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. from os import altsep, chmod, mkdir, remove, sep, stat, walk
  2. from os.path import dirname, exists, isdir, isfile, islink, join as joinpath
  3. from shutil import copyfile
  4. try:
  5. from os import symlink
  6. except ImportError:
  7. def symlink(src, dst): # pylint: disable-msg=W0613
  8. raise OSError('This platform does not support symbolic links')
  9. def scanTree(baseDir):
  10. '''Scans files and directories from the given base directory and iterates
  11. through the paths of the files and directories it finds; these paths are
  12. relative to the base directory.
  13. Directories will always be returned before any of the files they contain.
  14. The base directory itself is not returned.
  15. Hidden files and directories are not returned.
  16. All paths returned use the OS native separator character (os.sep),
  17. regardless of which separator characters were used in the arguments.
  18. Raises OSError if there is an I/O error scanning the base directory.
  19. '''
  20. if altsep is not None:
  21. # Make sure all paths use the OS native separator, so we can safely
  22. # compare paths and have consistent error messages.
  23. baseDir = baseDir.replace(altsep, sep)
  24. baseDir = baseDir.rstrip(sep)
  25. if not isdir(baseDir):
  26. raise OSError('Directory "%s" does not exist' % baseDir)
  27. def escalate(ex):
  28. raise OSError(
  29. 'Error scanning directory entry "%s": %s' % (ex.filename, ex)
  30. )
  31. for dirPath, dirNames, fileNames in walk(baseDir, onerror = escalate):
  32. # Skip hidden directories.
  33. # We are deleting items from the list we are iterating over; that
  34. # requires some extra care.
  35. index = 0
  36. while index < len(dirNames):
  37. if dirNames[index].startswith('.'):
  38. del dirNames[index]
  39. else:
  40. index += 1
  41. # Skip hidden files.
  42. fileNames = [ name for name in fileNames if not name.startswith('.') ]
  43. if dirPath == baseDir:
  44. relDir = ''
  45. else:
  46. assert dirPath.startswith(baseDir + sep), dirPath
  47. relDir = dirPath[len(baseDir) + 1 : ]
  48. yield relDir
  49. for fileName in fileNames:
  50. yield joinpath(relDir, fileName)
  51. def installDir(path):
  52. '''Creates the given path, excluding parent directories.
  53. The directory is created with permissions such that all users can read what
  54. is installed and only the owner can modify what is installed.
  55. If the given path already exists, nothing happens.
  56. '''
  57. if not isdir(path):
  58. # We have to do chmod() separately because the "mode" argument of
  59. # mkdir() is modified by umask.
  60. mkdir(path)
  61. chmod(path, 0o755)
  62. def _installDirsRec(path):
  63. '''Like installDirs(), except that "altsep" is not supported as directory
  64. separator in "path".
  65. '''
  66. path = path.rstrip(sep)
  67. if path and not isdir(path):
  68. index = path.rfind(sep)
  69. if index != -1:
  70. _installDirsRec(path[ : index])
  71. mkdir(path)
  72. chmod(path, 0o755)
  73. def installDirs(path):
  74. '''Creates the given path, including any parent directories if necessary.
  75. Any newly created directories are created with permissions such that all
  76. users can read what is installed and only the owner can modify what is
  77. installed.
  78. If the given path already exists, nothing happens.
  79. '''
  80. if altsep is not None:
  81. path = path.replace(altsep, sep)
  82. _installDirsRec(path)
  83. def installFile(srcPath, destPath):
  84. '''Copies a file from the given source path to the given destination path.
  85. The destination file is created with permissions such that all users can
  86. read (and execute, if appropriate) what is installed and only the owner
  87. can modify what is installed.
  88. Raises OSError if there is a problem reading or writing files.
  89. '''
  90. copyfile(srcPath, destPath)
  91. chmod(destPath, 0o755 if (stat(srcPath).st_mode & 0o100) else 0o644)
  92. def installSymlink(target, link):
  93. '''Creates a symbolic link with the given name to the given target.
  94. If a symbolic link with the given name already exists, it is replaced.
  95. If a different file type with the given name already exists, OSError is
  96. raised.
  97. Also raises OSError if this platform lacks os.symlink().
  98. '''
  99. if islink(link):
  100. remove(link)
  101. symlink(target, link)
  102. def installTree(srcDir, destDir, paths):
  103. '''Copies files and directories from the given source directory to the
  104. given destination directory. The given paths argument is a sequence of
  105. paths relative to the source directory; only those files and directories
  106. are copied. The scanTree() function is suitable to provide paths.
  107. Files and directories are created with permissions such that all users can
  108. read (and execute, if appropriate) what is installed and only the owner
  109. can modify what is installed.
  110. Raises OSError if there is a problem reading or writing files or
  111. directories.
  112. '''
  113. if not isdir(destDir):
  114. raise OSError('Destination directory "%s" does not exist' % destDir)
  115. for relPath in paths:
  116. if altsep is not None:
  117. relPath = relPath.replace(altsep, sep)
  118. srcPath = joinpath(srcDir, relPath)
  119. destPath = joinpath(destDir, relPath)
  120. if islink(srcPath):
  121. print('Skipping symbolic link:', srcPath)
  122. elif isdir(srcPath):
  123. _installDirsRec(destPath)
  124. elif isfile(srcPath):
  125. _installDirsRec(dirname(destPath))
  126. installFile(srcPath, destPath)
  127. elif exists(srcPath):
  128. print('Skipping unknown kind of file system entry:', srcPath)
  129. else:
  130. print('Skipping non-existing path:', srcPath)