3
"""Build a debootstrap script from a list of base packages and a control
4
file listing per-architecture overrides."""
11
class RequiredPackageNotInBase(Exception): pass
18
"""Read a file describing the base system on each architecture."""
21
if line.startswith('#') or len(line) == 0:
24
fields = line.split(':')
29
value = fields[1].strip()
30
packages = value.split()
32
if name.startswith('base-'):
34
if arch not in self.base:
36
self.base[arch].extend(packages)
45
self.arch_exclude = {}
46
self.arch_required = {}
49
"""Read an overrides file."""
52
if line.startswith('#') or len(line) == 0:
55
fields = line.split(':')
60
value = fields[1].strip()
61
packages = value.split()
64
# Exclude from all architectures (regular expressions)
66
self.exclude.append(re.compile(expr))
67
elif name.startswith('exclude-'):
68
# Exclude from one architecture (regular expressions)
70
if arch not in self.arch_exclude:
71
self.arch_exclude[arch] = []
73
self.arch_exclude[arch].append(re.compile(expr))
74
elif name == 'required':
75
# Required in first stage on all architectures
76
self.required.extend(packages)
77
elif name.startswith('required-'):
78
# Required in first stage on one architecture
80
if arch not in self.arch_required:
81
self.arch_required[arch] = []
82
self.arch_required[arch].extend(packages)
83
elif name.startswith('base-'):
84
# In base system (second stage) on one architecture
86
if arch not in self.arch_base:
87
self.arch_base[arch] = []
88
self.arch_base[arch].extend(packages)
93
for dist in sys.argv[1:]:
94
template_name = "%s.template" % dist
95
base_name = "%s.base" % dist
96
overrides_name = "%s.overrides" % dist
100
if os.path.exists(base_name):
101
base.read(open(base_name, 'r'))
104
overrides = Overrides()
105
if os.path.exists(overrides_name):
106
overrides.read(open(overrides_name, 'r'))
110
required_arch_indep = []
111
required_arch_dep = {}
113
for arch in base.base:
114
base_arch_dep[arch] = []
115
required_arch_dep[arch] = []
117
# Process excludes first.
118
for arch in base.base:
119
excludes = list(overrides.exclude)
120
if arch in overrides.arch_exclude:
121
excludes.extend(overrides.arch_exclude[arch])
123
for package in base.base[arch]:
124
for exclude in excludes:
125
if exclude.match(package):
128
new_base.append(package)
129
base.base[arch] = new_base
131
# Sketch out the whole base system.
133
for arch in base.base:
134
for package in base.base[arch]:
135
if package not in base_full:
136
base_full.append(package)
138
# Which packages are in the base system on only some architectures?
139
for package in base_full:
140
for arch in base.base:
141
if package not in base.base[arch]:
144
base_arch_indep.append(package)
146
# By set subtraction, get the architecture-dependent list for each
148
for arch in base.base:
149
for package in base.base[arch]:
150
if package not in base_arch_indep:
151
base_arch_dep[arch].append(package)
153
# Move architecture-independent requires. If they actually aren't
154
# available on all architectures, make them architecture-dependent
156
for package in overrides.required:
157
if package in base_arch_indep:
158
base_arch_indep.remove(package)
159
required_arch_indep.append(package)
161
for arch in base_arch_dep:
162
if package in base_arch_dep[arch]:
163
base_arch_dep[arch].remove(package)
164
required_arch_dep[arch].append(package)
165
# TODO: would like to raise an exception if it wasn't in
166
# base_arch_dep at all
168
# Move architecture-dependent requires.
169
for arch in overrides.arch_required:
170
for package in overrides.arch_required[arch]:
171
if package in base_arch_indep:
172
# Required on one architecture; base elsewhere.
173
base_arch_indep.remove(package)
174
for otherarch in base_arch_dep:
175
if arch != otherarch:
176
base_arch_dep[otherarch].append(package)
177
required_arch_dep[arch].append(package)
179
# Required on one architecture; may or may not be base
180
# elsewhere, but we don't need to care.
181
if package in base_arch_dep[arch]:
182
base_arch_dep[arch].remove(package)
183
required_arch_dep[arch].append(package)
185
raise RequiredPackageNotInBase, package
187
# Make substitutions in the template
188
template_handle = open(template_name, 'r')
189
template = template_handle.read()
190
template_handle.close()
192
updist = dist.upper()
193
template = template.replace("@%s_REQUIRED@" % updist, string.join(required_arch_indep))
194
template = template.replace("@%s_BASE@" % updist, string.join(base_arch_indep))
195
for arch in required_arch_dep:
196
template = template.replace("@%s_REQUIRED_%s@" % (updist, arch.upper()), string.join(required_arch_dep[arch]))
197
for arch in base_arch_dep:
198
template = template.replace("@%s_BASE_%s@" % (updist, arch.upper()), string.join(base_arch_dep[arch]))
200
output_handle = open(dist, 'w')
201
output_handle.write(template)
202
output_handle.close()
204
if __name__ == "__main__":