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