OXYGENHUB
◆ main openmsx / build / package-windows / harvest.py
5.6 KiB · Python · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
# Generates Windows resource header.
2
3
from optparse import OptionParser
4
from os import walk
5
from os.path import (
6
	basename, dirname, isfile, join as joinpath, relpath, split as splitpath
7
	)
8
from uuid import uuid4
9
10
indentSize = 2
11
12
excludedDirectories = ['.svn', 'CVS']
13
excludedFiles = ['node.mk']
14
15
# Bit of a hack, but it works
16
def isParentDir(child, parent):
17
	return '..' not in relpath(child, parent)
18
19
def makeFileId(guid):
20
	return 'file_' + guid
21
22
def makeDirectoryId(guid):
23
	return 'directory_' + guid
24
25
def makeComponentId(guid):
26
	return 'component_' + guid
27
28
def newGuid():
29
	return str(uuid4()).replace('-', '')
30
31
def walkPath(sourcePath):
32
	if isfile(sourcePath):
33
		yield dirname(sourcePath), [], [ basename(sourcePath) ]
34
	else:
35
		for dirpath, dirnames, filenames in walk(sourcePath):
36
			yield dirpath, dirnames, filenames
37
38
class WixFragment(object):
39
40
	def __init__(self, fileGenerator, componentGroup, directoryRef, virtualDir,
41
			excludedFile, win64):
42
		self.fileGenerator = fileGenerator
43
		self.componentGroup = componentGroup
44
		self.directoryRef = directoryRef
45
		self.virtualDir = virtualDir
46
		self.indentLevel = 0
47
		self.win64 = 'yes' if win64 else 'no'
48
49
		if excludedFile:
50
			# TODO: Modifying this global variable is an unexpected side effect.
51
			excludedFiles.append(excludedFile)
52
53
	def incrementIndent(self):
54
		self.indentLevel += indentSize
55
56
	def decrementIndent(self):
57
		self.indentLevel -= indentSize
58
59
	def indent(self, line):
60
		return ' ' * self.indentLevel + line
61
62
	def startElement(self, elementName, **args):
63
		line = self.indent(
64
			'<%s %s>' % (
65
				elementName,
66
				' '.join('%s="%s"' % item for item in args.items())
67
				)
68
			)
69
		self.incrementIndent()
70
		return line
71
72
	def endElement(self, elementName):
73
		self.decrementIndent()
74
		return self.indent('</%s>' % elementName)
75
76
	def yieldFragment(self):
77
		# List that stores the components we've added
78
		components = []
79
80
		# Stack that stores directories we've already visited
81
		stack = []
82
83
		# List that stores the virtual directories we added
84
		virtualstack = []
85
86
		yield self.indent(
87
			'<?xml version="1.0" encoding="utf-8"?>'
88
			)
89
		yield self.startElement(
90
			'Wix', xmlns = 'http://schemas.microsoft.com/wix/2006/wi'
91
			)
92
		yield self.startElement('Fragment')
93
		yield self.startElement('DirectoryRef', Id = self.directoryRef)
94
95
		# Add virtual directories
96
		if self.virtualDir:
97
			head = self.virtualDir
98
			while head:
99
				joinedPath = head
100
				head, tail_ = splitpath(head)
101
				virtualstack.insert(0, joinedPath)
102
			for path in virtualstack:
103
				componentId = 'directory_' + str(uuid4()).replace('-', '_')
104
				yield self.startElement(
105
					'Directory', Id = componentId, Name = basename(path)
106
					)
107
108
		# Walk the provided file list
109
		firstDir = True
110
		for dirpath, dirnames, filenames in self.fileGenerator:
111
112
			# Remove excluded sub-directories
113
			for exclusion in excludedDirectories:
114
				if exclusion in dirnames:
115
					dirnames.remove(exclusion)
116
117
			if firstDir:
118
				firstDir = False
119
			else:
120
				# Handle directory hierarchy appropriately
121
				while stack:
122
					popped = stack.pop()
123
					if isParentDir(dirpath, popped):
124
						stack.append(popped)
125
						break
126
					else:
127
						yield self.endElement('Directory')
128
129
				# Enter new directory
130
				stack.append(dirpath)
131
				yield self.startElement(
132
					'Directory', Id = makeDirectoryId(newGuid()),
133
					Name = basename(dirpath)
134
					)
135
136
			# Remove excluded files
137
			for exclusion in excludedFiles:
138
				if exclusion in filenames:
139
					filenames.remove(exclusion)
140
141
			# Process files
142
			for filename in filenames:
143
				guid = newGuid()
144
				componentId = makeComponentId(guid)
145
				sourcePath = joinpath(dirpath, filename)
146
147
				yield self.startElement(
148
					'Component', Id = componentId, Guid = guid,
149
					DiskId = '1', Win64 = self.win64
150
					)
151
				yield self.startElement(
152
					'File', Id = makeFileId(guid), Name = filename,
153
					Source = sourcePath
154
					)
155
				yield self.endElement('File')
156
157
				yield self.endElement('Component')
158
				components.append(componentId)
159
160
		# Drain pushed physical directories
161
		while stack:
162
			popped = stack.pop()
163
			yield self.endElement('Directory')
164
165
		# Drain pushed virtual directories
166
		while virtualstack:
167
			popped = virtualstack.pop()
168
			yield self.endElement('Directory')
169
170
		yield self.endElement('DirectoryRef')
171
		yield self.endElement('Fragment')
172
173
		# Emit ComponentGroup
174
		yield self.startElement('Fragment')
175
		yield self.startElement('ComponentGroup', Id = self.componentGroup)
176
		for component in components:
177
			yield self.startElement('ComponentRef', Id = component)
178
			yield self.endElement('ComponentRef')
179
		yield self.endElement('ComponentGroup')
180
		yield self.endElement('Fragment')
181
182
		yield self.endElement('Wix')
183
184
def generateWixFragment(
185
	sourcePath, componentGroup, directoryRef, virtualDir, excludedFile, win64
186
	):
187
	fileGenerator = walkPath(sourcePath)
188
	wf = WixFragment(
189
		fileGenerator, componentGroup, directoryRef, virtualDir, excludedFile,
190
		win64
191
		)
192
	return wf.yieldFragment()
193
194
def run():
195
	parser = OptionParser()
196
	parser.add_option(
197
		'-c', '--componentGroup', type = 'string', dest = 'componentGroup'
198
		)
199
	parser.add_option(
200
		'-r', '--directoryRef', type = 'string', dest = 'directoryRef'
201
		)
202
	parser.add_option(
203
		'-s', '--sourcePath', type = 'string', dest = 'sourcePath'
204
		)
205
	parser.add_option(
206
		'-v', '--virtualDir', type = 'string', dest = 'virtualDir'
207
		)
208
	parser.add_option(
209
		'-x', '--excludedFile', type = 'string', dest = 'excludedFile'
210
		)
211
	parser.add_option(
212
		'-w', '--win64', type = 'string', dest = 'win64'
213
		)
214
	options, args_ = parser.parse_args()
215
216
	for line in generateWixFragment(
217
		options.sourcePath, options.componentGroup, options.directoryRef,
218
		options.virtualDir, options.excludedFile, options.win64
219
		):
220
		print(line)
221
222
if __name__ == '__main__':
223
	run()