blob: 13bb6f44a076773d4e2dc2b0bf5e4b9771bf46e0 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import os
import os.path
import logging
import shutil
import tg
from tg import app_globals as g, tmpl_context as c
from allura.tasks import mail_tasks
from allura.lib.decorators import task
from allura.lib import helpers as h
from allura.model.repository import zipdir
log = logging.getLogger(__name__)
@task
def bulk_export(tools, filename=None, send_email=True, with_attachments=False):
'''
Export the current project data. Send notification to current user.
:param list tools: list of mount_points to export
:param str filename: optional filename to use
'''
# it's very handy to use c.* within a @task,
# but let's be explicit and keep it separate from the main code
return BulkExport().process(c.project, tools, c.user, filename, send_email, with_attachments)
class BulkExport:
def process(self, project, tools, user, filename=None, send_email=True, with_attachments=False):
export_filename = filename or project.bulk_export_filename()
tmp_path = os.path.join(
project.bulk_export_path(rootdir=tg.config.get('bulk_export_tmpdir', tg.config['bulk_export_path'])),
os.path.splitext(export_filename)[0], # e.g. test-backup-2018-06-26-210524 without the .zip
)
export_path = project.bulk_export_path(rootdir=tg.config['bulk_export_path'])
export_fullpath = os.path.join(export_path, export_filename)
if not os.path.exists(tmp_path):
os.makedirs(tmp_path)
if not os.path.exists(export_path):
os.makedirs(export_path)
apps = [project.app_instance(tool) for tool in tools]
exportable = self.filter_exportable(apps)
results = [self.export(tmp_path, app, with_attachments) for app in exportable]
exported = self.filter_successful(results)
if exported:
zipdir(tmp_path, export_fullpath)
shutil.rmtree(tmp_path.encode('utf8')) # must encode into bytes or it'll fail on non-ascii filenames
if not user:
log.info('No user. Skipping notification.')
return
if not send_email:
return
tmpl = g.jinja2_env.get_template('allura:templates/mail/bulk_export.html')
instructions = tg.config.get('bulk_export_download_instructions', '')
instructions = instructions.format(
project=project.shortname,
filename=export_filename,
c=c,
)
exported_names = [a.config.options.mount_point for a in exported]
tmpl_context = {
'instructions': instructions,
'project': project,
'tools': exported_names,
'not_exported_tools': list(set(tools) - set(exported_names)),
}
mail_tasks.send_system_mail_to_user(user,
'Bulk export for project %s completed' % project.shortname,
tmpl.render(tmpl_context))
def filter_exportable(self, apps):
return [app for app in apps if app and app.exportable]
def export(self, export_path, app, with_attachments=False):
tool = app.config.options.mount_point
json_file = os.path.join(export_path, '%s.json' % tool)
try:
with open(json_file, 'w', encoding='utf-8') as f:
app.bulk_export(f, export_path, with_attachments)
except Exception:
log.error('Error exporting: %s on %s', tool,
app.project.shortname, exc_info=True)
try:
os.remove(json_file)
except Exception:
pass
return None
else:
return app
def filter_successful(self, results):
return [result for result in results if result is not None]