You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by jo...@apache.org on 2014/01/06 16:18:40 UTC
[50/50] git commit: [#6992] Refactor bulk_export task some using
Boundaries concepts
[#6992] Refactor bulk_export task some using Boundaries concepts
Signed-off-by: Cory Johns <cj...@slashdotmedia.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/d2baf30f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/d2baf30f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/d2baf30f
Branch: refs/heads/cj/6992
Commit: d2baf30fcf0ab455050725b4461cd7798cfd329f
Parents: 18e8da1
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Thu Dec 19 20:22:58 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon Jan 6 15:16:51 2014 +0000
----------------------------------------------------------------------
Allura/allura/tasks/export_tasks.py | 153 ++++++++++++++-----------------
Allura/allura/tests/test_tasks.py | 51 +++--------
2 files changed, 85 insertions(+), 119 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/d2baf30f/Allura/allura/tasks/export_tasks.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tasks/export_tasks.py b/Allura/allura/tasks/export_tasks.py
index 2f286d0..3fd9499 100644
--- a/Allura/allura/tasks/export_tasks.py
+++ b/Allura/allura/tasks/export_tasks.py
@@ -44,89 +44,76 @@ def bulk_export(tools, filename=None, send_email=True):
'''
# it's very handy to use c.* within a @task,
# but let's be explicit and keep it separate from the main code
- return _bulk_export(c.project, tools, c.user, filename, send_email)
-
-
-def _bulk_export(project, tools, user, filename=None, send_email=True):
- export_filename = filename or project.bulk_export_filename()
- export_path = create_export_dir(project, export_filename)
- not_exported_tools = []
- for tool in tools or []:
- app = project.app_instance(tool)
- if not app:
- log.info('Can not load app for %s mount point. Skipping.' % tool)
- not_exported_tools.append(tool)
- continue
- if not app.exportable:
- log.info('Tool %s is not exportable. Skipping.' % tool)
- not_exported_tools.append(tool)
- continue
- log.info('Exporting %s...' % tool)
+ return BulkExport().process(c.project, tools, c.user, filename, send_email)
+
+
+class BulkExport(object):
+ def process(self, project, tools, user, filename=None, send_email=True):
+ export_filename = filename or project.bulk_export_filename()
+ export_path = self.get_export_path(project.bulk_export_path(), export_filename)
+ 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(export_path, app) for app in exportable]
+ exported = self.filter_successful(results)
+ if exported:
+ zipdir(export_path, os.path.join(os.path.dirname(export_path), export_filename))
+ shutil.rmtree(export_path)
+
+ 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)),
+ }
+ email = {
+ 'sender': unicode(tg.config['forgemail.return_path']),
+ 'fromaddr': unicode(tg.config['forgemail.return_path']),
+ 'reply_to': unicode(tg.config['forgemail.return_path']),
+ 'message_id': h.gen_message_id(),
+ 'destinations': [unicode(user._id)],
+ 'subject': u'Bulk export for project %s completed' % project.shortname,
+ 'text': tmpl.render(tmpl_context),
+ }
+ mail_tasks.sendmail.post(**email)
+
+ def get_export_path(self, export_base_path, export_filename):
+ """Create temporary directory for export files"""
+ # Name temporary directory after project shortname,
+ # thus zipdir() will use proper prefix inside the archive.
+ tmp_dir_suffix = os.path.splitext(export_filename)[0]
+ path = os.path.join(export_base_path, tmp_dir_suffix)
+ return path
+
+ def filter_exportable(self, apps):
+ return [app for app in apps if app and app.exportable]
+
+ def export(self, export_path, app):
+ tool = app.config.options.mount_point
+ json_file = os.path.join(export_path, '%s.json' % tool)
try:
- json_file = os.path.join(export_path, '%s.json' % tool)
with open(json_file, 'w') as f:
app.bulk_export(f)
- except:
- log.error('Something went wrong during export of %s' % tool, exc_info=True)
- not_exported_tools.append(tool)
- continue
-
- if tools and len(not_exported_tools) < len(tools):
- # If that fails, we need to let it fail
- # there won't be a valid zip file for the user to get.
- zip_and_cleanup(export_path, export_filename)
- else:
- log.error('Nothing to export')
- return None
-
- 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,
- )
- tmpl_context = {
- 'instructions': instructions,
- 'project': project,
- 'tools': list(set(tools) - set(not_exported_tools)),
- 'not_exported_tools': not_exported_tools,
- }
- email = {
- 'sender': unicode(tg.config['forgemail.return_path']),
- 'fromaddr': unicode(tg.config['forgemail.return_path']),
- 'reply_to': unicode(tg.config['forgemail.return_path']),
- 'message_id': h.gen_message_id(),
- 'destinations': [unicode(user._id)],
- 'subject': u'Bulk export for project %s completed' % project.shortname,
- 'text': tmpl.render(tmpl_context),
- }
- mail_tasks.sendmail.post(**email)
-
-
-def create_export_dir(project, export_filename):
- """Create temporary directory for export files"""
- # Name temporary directory after project shortname,
- # thus zipdir() will use proper prefix inside the archive.
- tmp_dir_suffix = os.path.splitext(export_filename)[0]
- path = os.path.join(project.bulk_export_path(), tmp_dir_suffix)
- if not os.path.exists(path):
- os.makedirs(path)
- return path
-
-
-def zip_and_cleanup(export_path, export_filename):
- """
- Zip exported data for a given path and filename.
- Copy it to proper location. Remove temporary files.
- """
- zipdir(export_path, os.path.join(os.path.dirname(export_path), export_filename))
-
- # cleanup
- shutil.rmtree(export_path)
+ except Exception as e:
+ log.error('Error exporting: %s on %s', tool, app.project.shortname, exc_info=True)
+ return None
+ else:
+ return app
+
+ def filter_successful(self, results):
+ return [result for result in results if result is not None]
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/d2baf30f/Allura/allura/tests/test_tasks.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_tasks.py b/Allura/allura/tests/test_tasks.py
index 13c6f7f..d908252 100644
--- a/Allura/allura/tests/test_tasks.py
+++ b/Allura/allura/tests/test_tasks.py
@@ -447,33 +447,29 @@ class TestExportTasks(unittest.TestCase):
project = M.Project.query.get(shortname='test')
shutil.rmtree(project.bulk_export_path(), ignore_errors=True)
- @mock.patch('allura.tasks.export_tasks.log')
- def test_bulk_export_invalid_tool(self, log):
- export_tasks.bulk_export([u'bugs', u'blog'])
- log.info.assert_any_call('Can not load app for bugs mount point. Skipping.')
- log.info.assert_any_call('Can not load app for blog mount point. Skipping.')
-
- @mock.patch('allura.tasks.export_tasks.log')
- @mock.patch('allura.tasks.export_tasks.M.Project.app_instance')
- @mock.patch('allura.tasks.export_tasks.mail_tasks')
- @td.with_tool('test', 'Tickets', 'bugs')
- @td.with_tool('test', 'Blog', 'blog')
- def test_bulk_export_not_exportable_tool(self, mail_tasks, app, log):
- app.return_value.exportable = False
- export_tasks.bulk_export([u'bugs', u'blog'])
- log.info.assert_any_call('Tool bugs is not exportable. Skipping.')
- log.info.assert_any_call('Tool blog is not exportable. Skipping.')
+ def test_bulk_export_filter_exportable(self):
+ exportable = mock.Mock(exportable=True)
+ not_exportable = mock.Mock(exportable=False)
+ BE = export_tasks.BulkExport()
+ self.assertEqual(BE.filter_exportable([None, exportable, not_exportable]), [exportable])
+
+ def test_bulk_export_filter_successful(self):
+ BE = export_tasks.BulkExport()
+ self.assertEqual(BE.filter_successful(['foo', None, '0']), ['foo', '0'])
+
+ def test_get_export_path(self):
+ BE = export_tasks.BulkExport()
+ path = BE.get_export_path('/tmp/bulk_export/p/test/', 'test-0.zip')
+ self.assertEqual(path, '/tmp/bulk_export/p/test/test-0')
@mock.patch('allura.model.project.Project.__json__')
@mock.patch('allura.tasks.export_tasks.shutil')
@mock.patch('allura.tasks.export_tasks.zipdir')
@mock.patch('forgewiki.wiki_main.ForgeWikiApp.bulk_export')
- @mock.patch('allura.tasks.export_tasks.log')
@td.with_wiki
- def test_bulk_export(self, log, wiki_bulk_export, zipdir, shutil, project_json):
+ def test_bulk_export(self, wiki_bulk_export, zipdir, shutil, project_json):
M.MonQTask.query.remove()
export_tasks.bulk_export([u'wiki'])
- log.info.assert_any_call('Exporting wiki...')
wiki_bulk_export.assert_called_once()
project_json.assert_called_once()
temp = '/tmp/bulk_export/p/test/test'
@@ -493,23 +489,6 @@ class TestExportTasks(unittest.TestCase):
assert_in('The following tools were exported:\n- wiki', text)
assert_in('Sample instructions for test', text)
- def test_create_export_dir(self):
- project = M.Project.query.get(shortname='test')
- export_path = project.bulk_export_path()
- export_filename = project.bulk_export_filename()
- path = export_tasks.create_export_dir(project, export_filename)
- assert_equal(path, '/tmp/bulk_export/p/test/test')
- assert os.path.exists(os.path.join(export_path, project.shortname))
-
- @onlyif(os.path.exists(tg.config.get('scm.repos.tarball.zip_binary', '/usr/bin/zip')), 'zip binary is missing')
- def test_zip_and_cleanup(self):
- project = M.Project.query.get(shortname='test')
- export_filename = project.bulk_export_filename()
- path = export_tasks.create_export_dir(project, export_filename)
- export_tasks.zip_and_cleanup(path, export_filename)
- assert not os.path.exists(path)
- assert os.path.exists(os.path.join(project.bulk_export_path(), 'test.zip'))
-
def test_bulk_export_status(self):
assert_equal(c.project.bulk_export_status(), None)
export_tasks.bulk_export.post(['wiki'])