summaryrefslogtreecommitdiff
blob: 560503d648806aa6cc8d4254d36382387c7c7e73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/usr/bin/env python
#
# script to automate creation of rEFInd configuration files
#
# Usage:
#
# refind-mkconfig
#
# This program is copyright (c) 2012 by David P. Crandall
# It is released under the terms of the GNU GPL, version 3.
#
# Revision history:
#
# 0.4.5 -- Initial version
#
# Note: version numbers match those of the rEFInd package
# with which this script first appeared.

import os, re
from collections import OrderedDict, deque
from string import Template

class _Template(Template):
	idpattern = '[0-9]+'

class _Parser(object):
	def __init__(self, files):
		self.files = files
		self.state = pattern
		self.stanzas = OrderedDict()
		self.header = None
		self.menu = None

	def process(self, lines):
		remaining = self.state.process(lines, self)
		if remaining:
			self.process(remaining)

	def getstanzas(self):
		for file in self.files:
			with open(file, 'r') as sf:
				lines = deque(sf.readlines())
				self.process(lines)
		return self.stanzas

class _Pattern(object):
	def __init__(self):
		self.header = re.compile("^\[(.+)\]")

	def process(self, lines, parser):
		line = lines.popleft()
		match = self.header.match(line)
		if match:
			parser.header = match.group(1)
			parser.stanzas[parser.header] = OrderedDict() if parser.header not in parser.stanzas
			parser.state = transition
		return lines

class _Menustart(object):
	def __init__():
		self.start = re.compile("^menuentry\s+(.+)\s+\{")

	def process(self, lines, parser):
		line = lines.popleft()
		match = self.start.match(line)
		if match:
			parser.menu = match.group(1)
			parser.stanzas[parser.header][parser.menu] = [line]
			parser.state = menu_end
		return lines

class _Menuend(object):
	def __init__():
		self.end = re.compile("^\}")

	def process(self, lines, parser):
		line = lines.popleft()
		parser.stanzas[parser.header][parser.menu].append(line)
		if self.end.match(line):
			parser.state = transition
		return lines

class _Transition(object):
	def process(self, lines, parser):
		if pattern.header.match(lines[0]):
			parser.state = pattern
		elif menu_start.start.match(lines[0])
			parser.state = menu_start
		else
			discard = lines.popleft()
		return lines

class Mkconfig(object):
	def __init__(self):
		self.efi = self._findEFI()
		self.conf = os.path.join(self.efi, "/EFI/refind/refind.test")
		self.comment = re.compile('^\s*#')
		self.stanzas = OrderedDict()
		self.stanzaFiles = sum([[os.path.join(r, f) for f in fl] 
			for r, d, fl in os.walk("/etc/refind.d")], [])

		blockdir = re.compile('^' + self.efi + '/EFI/(refind|tools)')
		stripdir = re.compile('^' + self.efi)
		efiFiles = [[os.path.join(r, f) for f in fl] 
			for r, d, fl in os.walk(self.efi) if not blockdir.match(r)]
		# flatten generated lists
		efiFiles = sum(efiFiles, [])
		# sort by modification date of files, newest first
		efiFiles = sorted(efiFiles, reverse=True, key=lambda i: os.path.getmtime(i))
		# strip mount path
		self.efiFiles = [stripdir.sub('', f) for f in efiFiles]

	def _findEFI(self):
		if os.path.ismount("/boot/efi"):
			mntpath = os.path.abspath("/boot/efi")
		elif os.path.ismount("/boot"):
			mntpath = os.path.abspath("/boot")
		else
			print "The EFI partition could not be found at /boot or /boot/efi.  Exiting"
			exit
		with open("/proc/mounts") as mnts:
			for line in mnts:
				words = re.split('\s+', line)
				if words[1] == mntpath:
					if words[2] == "vfat":
						return mntpath
			print "EFI partition must be vfat, but the filesystem is " + words[3] + ".  Exiting"
			exit

	def _getstanzas(self):
		p = 
		for file in self.stanzaFiles:
			with open(file, 'r') as sf:
				lines = sf.readlines()
								

	def writeGlobalOptions(self):
		with open(self.conf, 'w') as newconf:
			newconf.write("# This file has been automatically generated by refind-mkconfig.\n")
			newconf.write("# Manual edits will be overwritten the next time refind-mkconfig\n")
			newconf.write("# is invoked.  To change settings, edit /etc/default/refind and\n")
			newconf.write("# the files located at /etc/refind.d.\n\n")
			# Get global options
			newconf.write("# Global options\n")
			with open("/etc/default/refind") as default:
				for line in default:
					if NOT self.comment.match(line):
						newconf.write(line + "\n")

	def writeStanzas(self):
		# Get OS stanzas
		with open(self.conf, 'a') as newconf:
			newconf.write("\n# OS stanzas\n\n")
			p = _Parser(self.stanzaFiles)
			self.stanzas = p.getstanzas
			for pk in self.stanzas:
				pattern = re.compile(pk)
				for file in self.efiFiles:
					match = pattern.match(file)
					if match:
						values = {str(i): match.group(i) for i in range(pattern.groups)}
						for mk in self.stanzas[pk]:
							for line in self.stanzas[pk][mk]:
								t = _Template(line)
								newconf.write(t.substitute(values))
							newconf.write("\n")

pattern = _Pattern()
menu_start = _Menustart()
menu_end = _Menuend()
transition = _Transition()

if __name__ == '__main__':
	cfg = Mkconfig()
	cfg.writeGlobalOptions
	cfg.writeStanzas
	print "New refind.conf written to " + cfg.efi