diff --git a/bootstrapvz/base/bootstrapinfo.py b/bootstrapvz/base/bootstrapinfo.py index a14e7ff..a5bf9f2 100644 --- a/bootstrapvz/base/bootstrapinfo.py +++ b/bootstrapvz/base/bootstrapinfo.py @@ -83,6 +83,9 @@ class BootstrapInformation(object): # so that tasks may add to that list without having to fiddle with apt source list files. from pkg.sourceslist import SourceLists self.source_lists = SourceLists(self.manifest_vars) + # Keep a list of apt preferences + from pkg.preferenceslist import PreferenceLists + self.preference_lists = PreferenceLists(self.manifest_vars) # Keep a list of packages that should be installed, tasks can add and remove things from this list from pkg.packagelist import PackageList self.packages = PackageList(self.manifest_vars, self.source_lists) diff --git a/bootstrapvz/base/manifest-schema.json b/bootstrapvz/base/manifest-schema.json index ebc76ee..36b887a 100644 --- a/bootstrapvz/base/manifest-schema.json +++ b/bootstrapvz/base/manifest-schema.json @@ -57,6 +57,33 @@ "additionalProperties": false, "minItems": 1 }, + "preferences": { + "type": "object", + "patternProperties": { + "^[^\/\\0]+$": { + "type": "array", + "items": { + "type": "object", + "properties": { + "pin": { + "type": "string" + }, + "package": { + "type": "string" + }, + "pin-priority": { + "type": "integer" + } + }, + "required": ["pin", "package", "pin-priority"], + "additionalProperties": false + }, + "minItems": 1 + } + }, + "additionalProperties": false, + "minItems": 1 + }, "trusted-keys": { "type": "array", "items": { "$ref": "#/definitions/absolute_path" }, diff --git a/bootstrapvz/base/pkg/preferenceslist.py b/bootstrapvz/base/pkg/preferenceslist.py new file mode 100644 index 0000000..46ee63c --- /dev/null +++ b/bootstrapvz/base/pkg/preferenceslist.py @@ -0,0 +1,49 @@ + + +class PreferenceLists(object): + """Represents a list of preferences lists for apt + """ + + def __init__(self, manifest_vars): + """ + Args: + manifest_vars (dict): The manifest variables + """ + # A dictionary with the name of the file in preferences.d as the key + # That values are lists of Preference objects + self.preferences = {} + # Save the manifest variables, we need the later on + self.manifest_vars = manifest_vars + + def add(self, name, preferences): + """Adds a preference to the apt preferences list + + Args: + name (str): Name of the file in preferences.list.d, may contain manifest vars references + preferences (object): The preferences + """ + name = name.format(**self.manifest_vars) + self.preferences[name] = [Preference(p) for p in preferences] + + +class Preference(object): + """Represents a single preference + """ + + def __init__(self, preference): + """ + Args: + preference (dict): A apt preference dictionary + + Raises: + PreferenceError + """ + self.preference = preference + + def __str__(self): + """Convert the object into a preference block + + Returns: + string. + """ + return "Package: {package}\nPin: {pin}\nPin-Priority: {pin-priority}\n".format(**self.preference) diff --git a/bootstrapvz/common/task_sets.py b/bootstrapvz/common/task_sets.py index dbf09ef..5c982ec 100644 --- a/bootstrapvz/common/task_sets.py +++ b/bootstrapvz/common/task_sets.py @@ -63,6 +63,9 @@ def get_apt_set(manifest): base.append(apt.AddManifestSources) if 'trusted-keys' in manifest.packages: base.append(apt.InstallTrustedKeys) + if 'preferences' in manifest.packages: + base.append(apt.AddManifestPreferences) + base.append(apt.WritePreferences) if 'install' in manifest.packages: base.append(packages.AddManifestPackages) if manifest.packages.get('install_standard', False): diff --git a/bootstrapvz/common/tasks/apt.py b/bootstrapvz/common/tasks/apt.py index 95b1e34..ddcfb5e 100644 --- a/bootstrapvz/common/tasks/apt.py +++ b/bootstrapvz/common/tasks/apt.py @@ -33,6 +33,16 @@ class AddDefaultSources(Task): info.source_lists.add('main', 'deb-src {apt_mirror} {system.release}-updates ' + sections) +class AddManifestPreferences(Task): + description = 'Adding preferences from the manifest' + phase = phases.preparation + + @classmethod + def run(cls, info): + for name, preferences in info.manifest.packages['preferences'].iteritems(): + info.preference_lists.add(name, preferences) + + class InstallTrustedKeys(Task): description = 'Installing trusted keys' phase = phases.package_installation @@ -63,6 +73,23 @@ class WriteSources(Task): source_list.write('{line}\n'.format(line=str(source))) +class WritePreferences(Task): + description = 'Writing aptitude preferences to disk' + phase = phases.package_installation + predecessors = [WriteSources] + + @classmethod + def run(cls, info): + for name, preferences in info.preference_lists.preferences.iteritems(): + if name == 'main': + list_path = os.path.join(info.root, 'etc/apt/preferences') + else: + list_path = os.path.join(info.root, 'etc/apt/preferences.d/', name) + with open(list_path, 'w') as preference_list: + for preference in preferences: + preference_list.write('{preference}\n'.format(preference=str(preference))) + + class DisableDaemonAutostart(Task): description = 'Disabling daemon autostart' phase = phases.package_installation diff --git a/docs/base/pkg.rst b/docs/base/pkg.rst index 8159ad1..1a8db8b 100644 --- a/docs/base/pkg.rst +++ b/docs/base/pkg.rst @@ -15,6 +15,12 @@ Sources list :members: :private-members: +Preferences list +------------ +.. automodule:: bootstrapvz.base.pkg.preferenceslist + :members: + :private-members: + Exceptions ---------- .. automodule:: bootstrapvz.base.pkg.exceptions