diff --git a/actions/backups b/actions/backups index f0364abef..5a79bc01f 100755 --- a/actions/backups +++ b/actions/backups @@ -21,6 +21,7 @@ Configuration helper for backups. """ import argparse +import glob import json import os import subprocess @@ -57,8 +58,13 @@ def parse_arguments(): list_exports = subparsers.add_parser( 'list-exports', help='List exported backup archive files') - list_exports.add_argument('--locations', nargs='+', - help='list of locations to check') + list_exports.add_argument('--location', required=True, + help='location to check') + + restore = subparsers.add_parser( + 'restore', help='Restore files from an exported archive') + restore.add_argument('--filename', help='Tarball file name', required=True) + subparsers.required = True return parser.parse_args() @@ -121,17 +127,27 @@ def subcommand_export(arguments): def subcommand_list_exports(arguments): """List exported backup archive files.""" - archive_files = [] - for location in arguments.locations: - backup_path = location - if backup_path[-1] != '/': - backup_path += '/' - backup_path += 'FreedomBox-backups/' - if os.path.exists(backup_path): - for filename in os.listdir(backup_path): - archive_files.append(os.path.join(backup_path, filename)) + exports = [] + path = arguments.location + if path[-1] != '/': + path += '/' - print(json.dumps(archive_files)) + path += 'FreedomBox-backups/' + if os.path.exists(path): + for filename in glob.glob(path + '*.tar.gz'): + exports.append(os.path.basename(filename)) + + print(json.dumps(exports)) + + +def subcommand_restore(arguments): + """Restore files from an exported archive.""" + prev_dir = os.getcwd() + try: + os.chdir('/') + subprocess.run(['tar', 'xf', arguments.filename], check=True) + finally: + os.chdir(prev_dir) def main(): diff --git a/plinth/modules/backups/__init__.py b/plinth/modules/backups/__init__.py index d38e37e9c..68ff63e62 100644 --- a/plinth/modules/backups/__init__.py +++ b/plinth/modules/backups/__init__.py @@ -76,11 +76,6 @@ def delete_archive(name): actions.superuser_run('backups', ['delete', '--name', name]) -def extract_archive(name, destination): - actions.superuser_run( - 'backups', ['extract', '--name', name, '--destination', destination]) - - def export_archive(name, location): if location[-1] != '/': location += '/' @@ -102,9 +97,27 @@ def get_export_locations(): return locations -def list_export_files(): - """Return a list of exported backup archives found in storage locations.""" - locations = [x[0] for x in get_export_locations()] - command = ['list-exports', '--locations'] + locations - output = actions.superuser_run('backups', command) - return json.loads(output) +def get_export_files(): + """Return a dict of exported backup archives found in storage locations.""" + locations = get_export_locations() + export_files = {} + for location in locations: + output = actions.superuser_run( + 'backups', ['list-exports', '--location', location[0]]) + export_files[location[1]] = json.loads(output) + + return export_files + + +def restore_exported(label, name): + """Restore files from exported backup archive.""" + locations = get_export_locations() + for location in locations: + if location[1] == label: + filename = location[0] + if filename[-1] != '/': + filename += '/' + filename += 'FreedomBox-backups/' + name + actions.superuser_run( + 'backups', ['restore', '--filename', filename]) + break diff --git a/plinth/modules/backups/forms.py b/plinth/modules/backups/forms.py index d8ec95b9c..79297c6c4 100644 --- a/plinth/modules/backups/forms.py +++ b/plinth/modules/backups/forms.py @@ -37,12 +37,6 @@ class CreateArchiveForm(forms.Form): 'backup repository.')) -class ExtractArchiveForm(forms.Form): - path = forms.CharField(label=_('Path'), strip=True, help_text=_( - 'Disk path to a folder on this server where the archive will be ' - 'extracted.')) - - class ExportArchiveForm(forms.Form): disk = forms.ChoiceField( label=_('Disk'), widget=forms.RadioSelect(), diff --git a/plinth/modules/backups/templates/backups.html b/plinth/modules/backups/templates/backups.html index 4f40c9e21..f42e4b74b 100644 --- a/plinth/modules/backups/templates/backups.html +++ b/plinth/modules/backups/templates/backups.html @@ -52,7 +52,7 @@
{% trans 'No archives currently exist.' %}
{% else %}| {% trans "Name" %} | @@ -67,18 +67,14 @@{{ archive.name }} | {{ archive.time }} | - - {% trans "Extract" %} - - {% trans "Export" %} + {% trans "Export" %} - + href="{% url 'backups:delete' archive.name %}"> + |
|---|
| {% trans "Location" %} | {% trans "Name" %} | +|
|---|---|---|
| {{ export }} | -||
| {{ label }} | +{{ name }} | ++ + {% trans "Restore" %} + + | +
{% trans "Restore data from this archive?" %}
+ +| {% trans "Location" %} | +{% trans "Name" %} | + + +
|---|---|
| {{ label }} | +{{ name }} | +
+
+ + +{% endblock %} diff --git a/plinth/modules/backups/urls.py b/plinth/modules/backups/urls.py index 12b0e578a..68617d855 100644 --- a/plinth/modules/backups/urls.py +++ b/plinth/modules/backups/urls.py @@ -20,16 +20,16 @@ URLs for the backups module. from django.conf.urls import url -from .views import IndexView, CreateArchiveView, DeleteArchiveView, \ - ExtractArchiveView, ExportArchiveView +from .views import IndexView, CreateArchiveView, ExportArchiveView, \ + DeleteArchiveView, RestoreView urlpatterns = [ url(r'^sys/backups/$', IndexView.as_view(), name='index'), url(r'^sys/backups/create/$', CreateArchiveView.as_view(), name='create'), - url(r'^sys/backups/(?P