diff --git a/actions/backups b/actions/backups index 36a348b93..f0a272842 100755 --- a/actions/backups +++ b/actions/backups @@ -25,6 +25,7 @@ import glob import json import os import subprocess +import tarfile REPOSITORY = '/var/lib/freedombox/borgbackup' @@ -62,6 +63,12 @@ def parse_arguments(): list_exports.add_argument('--location', required=True, help='location to check') + get_export_apps = subparsers.add_parser( + 'get-export-apps', + help='Get list of apps included in exported archive file') + get_export_apps.add_argument( + '--filename', help='Tarball file name', required=True) + restore = subparsers.add_parser( 'restore', help='Restore files from an exported archive') restore.add_argument('--filename', help='Tarball file name', required=True) @@ -144,6 +151,23 @@ def subcommand_list_exports(arguments): print(json.dumps(exports)) +def subcommand_get_export_apps(arguments): + """Get list of apps included in exported archive file.""" + manifest = None + with tarfile.open(arguments.filename) as t: + filenames = t.getnames() + for name in filenames: + if 'var/lib/plinth/backups-manifests/' in name \ + and name.endswith('.json'): + manifest_data = t.extractfile(name).read() + manifest = json.loads(manifest_data) + break + + if manifest: + for app in manifest: + print(app['name']) + + def subcommand_restore(arguments): """Restore files from an exported archive.""" prev_dir = os.getcwd() diff --git a/plinth/modules/backups/__init__.py b/plinth/modules/backups/__init__.py index fc0ccaddf..cb7dfb419 100644 --- a/plinth/modules/backups/__init__.py +++ b/plinth/modules/backups/__init__.py @@ -140,7 +140,7 @@ def get_export_files(): return export_files -def _find_exported_archive(disk_label, archive_name): +def find_exported_archive(disk_label, archive_name): """Return the full path for the exported archive file.""" path = None locations = get_export_locations() @@ -155,9 +155,16 @@ def _find_exported_archive(disk_label, archive_name): return path +def get_export_apps(filename): + """Get list of apps included in exported archive file.""" + output = actions.superuser_run( + 'backups', ['get-export-apps', '--filename', filename]) + return output.splitlines() + + def restore_exported(label, name, apps=None): """Restore files from exported backup archive.""" - filename = _find_exported_archive(label, name) + filename = find_exported_archive(label, name) if filename: # TODO: Use backups API. actions.superuser_run( diff --git a/plinth/modules/backups/forms.py b/plinth/modules/backups/forms.py index e53745a7e..b94aea999 100644 --- a/plinth/modules/backups/forms.py +++ b/plinth/modules/backups/forms.py @@ -67,9 +67,8 @@ class RestoreForm(forms.Form): def __init__(self, *args, **kwargs): """Initialize the form with selectable apps.""" + apps = kwargs.pop('apps') super().__init__(*args, **kwargs) - apps = _list_of_all_apps_for_backup() - # TODO: Only list apps included in the backup file. self.fields['selected_apps'].choices = [ (app[0], app[1].name) for app in apps] self.fields['selected_apps'].initial = [app[0] for app in apps] diff --git a/plinth/modules/backups/views.py b/plinth/modules/backups/views.py index a00cbc31d..2e6e415bc 100644 --- a/plinth/modules/backups/views.py +++ b/plinth/modules/backups/views.py @@ -30,6 +30,7 @@ from django.views.generic import FormView, TemplateView from urllib.parse import unquote from plinth.modules import backups +from . import find_exported_archive, get_export_apps from .backups import _list_of_all_apps_for_backup from .forms import CreateArchiveForm, ExportArchiveForm, RestoreForm @@ -133,6 +134,31 @@ class RestoreView(SuccessMessageMixin, FormView): success_url = reverse_lazy('backups:index') success_message = _('Restored files from backup.') + def collect_data(self, label, name): + """Save some data used to instantiate the form.""" + self.label = unquote(label) + self.name = unquote(name) + self.filename = find_exported_archive(self.label, self.name) + self.installed_apps = _list_of_all_apps_for_backup() + self.included_apps = get_export_apps(self.filename) + + def get(self, request, *args, **kwargs): + """Save request parameters for later.""" + self.collect_data(kwargs['label'], kwargs['name']) + return super().get(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + """Save request parameters for later.""" + self.collect_data(kwargs['label'], kwargs['name']) + return super().post(request, *args, **kwargs) + + def get_form_kwargs(self): + """Pass additional keyword args for instantiating the form.""" + kwargs = super().get_form_kwargs() + kwargs['apps'] = [ + x for x in self.installed_apps if x[0] in self.included_apps] + return kwargs + def get_context_data(self, **kwargs): """Return additional context for rendering the template.""" context = super().get_context_data(**kwargs)