From 1df2588b23e3c30b66a75f8b10ad51b45de62d49 Mon Sep 17 00:00:00 2001 From: Anders Ingemann Date: Sat, 12 Dec 2015 23:36:08 +0100 Subject: [PATCH] Add option to exclude /usr/share/doc The bootstrap exclude script has also been generalize in the process --- bootstrapvz/plugins/minimize_size/__init__.py | 18 ++- .../plugins/minimize_size/manifest-schema.yml | 2 + .../plugins/minimize_size/tasks/dpkg.py | 113 +++++++++++++----- manifests/examples/docker/jessie.yml | 1 + 4 files changed, 95 insertions(+), 39 deletions(-) diff --git a/bootstrapvz/plugins/minimize_size/__init__.py b/bootstrapvz/plugins/minimize_size/__init__.py index 3e7fb44..913e734 100644 --- a/bootstrapvz/plugins/minimize_size/__init__.py +++ b/bootstrapvz/plugins/minimize_size/__init__.py @@ -32,13 +32,19 @@ def resolve_tasks(taskset, manifest): taskset.add(tasks.apt.AptGzipIndexes) if apt.get('autoremove_suggests', False): taskset.add(tasks.apt.AptAutoremoveSuggests) + filter_tasks = [tasks.dpkg.CreateDpkgCfg, + tasks.dpkg.InitializeBootstrapFilterList, + tasks.dpkg.CreateBootstrapFilterScripts, + tasks.dpkg.DeleteBootstrapFilterScripts, + ] if 'locales' in apt: - taskset.update([tasks.dpkg.CreateBootstrapFilterScripts, - tasks.dpkg.DeleteBootstrapFilterScripts, - tasks.dpkg.FilterLocales, - ]) + taskset.update(filter_tasks) + taskset.add(tasks.dpkg.FilterLocales) + if apt.get('exclude_docs', False): + taskset.update(filter_tasks) + taskset.add(tasks.dpkg.ExcludeDocs) def resolve_rollback_tasks(taskset, manifest, completed, counter_task): - counter_task(taskset, tasks.AddFolderMounts, tasks.RemoveFolderMounts) - counter_task(taskset, tasks.CreateBootstrapFilterScripts, tasks.DeleteBootstrapFilterScripts) + counter_task(taskset, tasks.mounts.AddFolderMounts, tasks.mounts.RemoveFolderMounts) + counter_task(taskset, tasks.dpkg.CreateBootstrapFilterScripts, tasks.dpkg.DeleteBootstrapFilterScripts) diff --git a/bootstrapvz/plugins/minimize_size/manifest-schema.yml b/bootstrapvz/plugins/minimize_size/manifest-schema.yml index 268791e..9483a92 100644 --- a/bootstrapvz/plugins/minimize_size/manifest-schema.yml +++ b/bootstrapvz/plugins/minimize_size/manifest-schema.yml @@ -28,6 +28,8 @@ properties: minItems: 1 items: type: string + exclude_docs: + type: boolean type: object additionalProperties: false type: object diff --git a/bootstrapvz/plugins/minimize_size/tasks/dpkg.py b/bootstrapvz/plugins/minimize_size/tasks/dpkg.py index 1f5c1c0..ff75b13 100644 --- a/bootstrapvz/plugins/minimize_size/tasks/dpkg.py +++ b/bootstrapvz/plugins/minimize_size/tasks/dpkg.py @@ -8,6 +8,25 @@ import shutil from . import assets +class CreateDpkgCfg(Task): + description = 'Creating /etc/dpkg/dpkg.cfg.d before bootstrapping' + phase = phases.os_installation + successors = [bootstrap.Bootstrap] + + @classmethod + def run(cls, info): + os.makedirs(os.path.join(info.root, 'etc/dpkg/dpkg.cfg.d')) + + +class InitializeBootstrapFilterList(Task): + description = 'Initializing the bootstrapping filter list' + phase = phases.preparation + + @classmethod + def run(cls, info): + info._minimize_size['bootstrap_filter'] = {'exclude': [], 'include': []} + + class CreateBootstrapFilterScripts(Task): description = 'Creating the bootstrapping locales filter script' phase = phases.os_installation @@ -29,46 +48,23 @@ class CreateBootstrapFilterScripts(Task): shutil.copy(os.path.join(assets, 'bootstrap-files-filter.sh'), filter_script) sed_i(bootstrap_script, r'BOOTSTRAP_FILES_FILTER_PATH', filter_script) - sed_i(filter_script, r'EXCLUDE_PATTERN', "./usr/share/locale/.\+\|./usr/share/man/.\+") - keep_files = ['./usr/share/locale/locale.alias', - './usr/share/man/man1', - './usr/share/man/man2', - './usr/share/man/man3', - './usr/share/man/man4', - './usr/share/man/man5', - './usr/share/man/man6', - './usr/share/man/man7', - './usr/share/man/man8', - './usr/share/man/man9', - ] - locales = info.manifest.plugins['minimize_size']['apt']['locales'] - keep_files.extend(map(lambda l: './usr/share/locale/' + l + '/', locales)) - keep_files.extend(map(lambda l: './usr/share/man/' + l + '/', locales)) - - sed_i(filter_script, r'INCLUDE_PATHS', "\n".join(keep_files)) + filter_lists = info._minimize_size['bootstrap_filter'] + exclude_list = '\|'.join(map(lambda p: '.' + p + '.\+', filter_lists['exclude'])) + include_list = '\n'.join(map(lambda p: '.' + p, filter_lists['include'])) + sed_i(filter_script, r'EXCLUDE_PATTERN', exclude_list) + sed_i(filter_script, r'INCLUDE_PATHS', include_list) os.chmod(filter_script, 0755) info.bootstrap_script = bootstrap_script info._minimize_size['filter_script'] = filter_script -class DeleteBootstrapFilterScripts(Task): - description = 'Deleting the bootstrapping locales filter script' - phase = phases.cleaning - successors = [workspace.DeleteWorkspace] - - @classmethod - def run(cls, info): - os.remove(info._minimize_size['filter_script']) - del info._minimize_size['filter_script'] - os.remove(info.bootstrap_script) - - class FilterLocales(Task): - description = 'Configuring dpkg to only include specific locales/manpages when installing packages' + description = 'Configuring dpkg and debootstrap to only include specific locales/manpages when installing packages' phase = phases.os_installation - successors = [bootstrap.Bootstrap] + predecessors = [CreateDpkgCfg] + successors = [CreateBootstrapFilterScripts] # Snatched from: # https://github.com/docker/docker/blob/1d775a54cc67e27f755c7338c3ee938498e845d7/contrib/mkimage/debootstrap # and @@ -76,8 +72,30 @@ class FilterLocales(Task): @classmethod def run(cls, info): - # This is before we start bootstrapping, so we create dpkg.cfg.d manually - os.makedirs(os.path.join(info.root, 'etc/dpkg/dpkg.cfg.d')) + # Filter when debootstrapping + info._minimize_size['bootstrap_filter']['exclude'].extend([ + '/usr/share/locale/', + '/usr/share/man/', + ]) + + locales = info.manifest.plugins['minimize_size']['apt']['locales'] + info._minimize_size['bootstrap_filter']['include'].extend([ + '/usr/share/locale/locale.alias', + '/usr/share/man/man1', + '/usr/share/man/man2', + '/usr/share/man/man3', + '/usr/share/man/man4', + '/usr/share/man/man5', + '/usr/share/man/man6', + '/usr/share/man/man7', + '/usr/share/man/man8', + '/usr/share/man/man9', + ] + + map(lambda l: '/usr/share/locale/' + l + '/', locales) + + map(lambda l: '/usr/share/man/' + l + '/', locales) + ) + + # Filter when installing things with dpkg locale_lines = ['path-exclude=/usr/share/locale/*', 'path-include=/usr/share/locale/locale.alias'] manpages_lines = ['path-exclude=/usr/share/man/*', @@ -94,3 +112,32 @@ class FilterLocales(Task): locale_filter.write('\n'.join(locale_lines) + '\n') with open(manpages_path, 'w') as manpages_filter: manpages_filter.write('\n'.join(manpages_lines) + '\n') + + +class ExcludeDocs(Task): + description = 'Configuring dpkg and debootstrap to not install additional documentation for packages' + phase = phases.os_installation + predecessors = [CreateDpkgCfg] + successors = [CreateBootstrapFilterScripts] + + @classmethod + def run(cls, info): + # "Packages must not require the existence of any files in /usr/share/doc/ in order to function [...]." + # Source: https://www.debian.org/doc/debian-policy/ch-docs.html + # So doing this should cause no problems. + info._minimize_size['bootstrap_filter']['exclude'].append('/usr/share/doc/') + exclude_docs_path = os.path.join(info.root, 'etc/dpkg/dpkg.cfg.d/10exclude-docs') + with open(exclude_docs_path, 'w') as exclude_docs: + exclude_docs.write('path-exclude=/usr/share/doc/*\n') + + +class DeleteBootstrapFilterScripts(Task): + description = 'Deleting the bootstrapping locales filter script' + phase = phases.cleaning + successors = [workspace.DeleteWorkspace] + + @classmethod + def run(cls, info): + os.remove(info._minimize_size['filter_script']) + del info._minimize_size['filter_script'] + os.remove(info.bootstrap_script) diff --git a/manifests/examples/docker/jessie.yml b/manifests/examples/docker/jessie.yml index 67ed959..13e94bc 100644 --- a/manifests/examples/docker/jessie.yml +++ b/manifests/examples/docker/jessie.yml @@ -34,3 +34,4 @@ plugins: locales: - en - en_US + exclude_docs: true