You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by tv...@apache.org on 2013/08/28 21:30:45 UTC

[01/13] git commit: [#6526] Fix typo

Updated Branches:
  refs/heads/master 09f02903f -> 6769dc236


[#6526] Fix typo

Signed-off-by: Tim Van Steenburgh <tv...@gmail.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/6ff3125c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/6ff3125c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/6ff3125c

Branch: refs/heads/master
Commit: 6ff3125c01544dffb7fe63a5efd14439e7b6d72d
Parents: 8378ac0
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Tue Aug 27 13:38:31 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Tue Aug 27 17:24:58 2013 +0000

----------------------------------------------------------------------
 ForgeImporters/forgeimporters/google/__init__.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6ff3125c/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
index ad5f8e5..849f924 100644
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ b/ForgeImporters/forgeimporters/google/__init__.py
@@ -1,4 +1,4 @@
-#       LNicensed to the Apache Software Foundation (ASF) under one
+#       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


[12/13] git commit: [#6611] provide mechanism to disable any allura entry point

Posted by tv...@apache.org.
[#6611] provide mechanism to disable any allura entry point


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/1581f299
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/1581f299
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/1581f299

Branch: refs/heads/master
Commit: 1581f299c20aa4babfa8a5a1f781625e49534346
Parents: 10cb90c
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Wed Aug 28 19:05:30 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Wed Aug 28 19:05:38 2013 +0000

----------------------------------------------------------------------
 Allura/allura/command/base.py                    |  3 +--
 Allura/allura/config/resources.py                |  6 ++++--
 Allura/allura/controllers/project.py             |  4 ++--
 Allura/allura/ext/admin/admin_main.py            |  2 +-
 Allura/allura/lib/app_globals.py                 |  2 +-
 Allura/allura/lib/custom_middleware.py           |  4 ++--
 Allura/allura/lib/helpers.py                     | 12 +++++++++++-
 Allura/allura/lib/package_path_loader.py         |  7 +++----
 Allura/allura/model/auth.py                      |  1 -
 Allura/docs/extending.rst                        | 10 +++++++++-
 ForgeImporters/forgeimporters/base.py            | 10 ++++------
 ForgeImporters/forgeimporters/tests/test_base.py |  8 ++++----
 scripts/rethumb.py                               |  6 ++++--
 13 files changed, 46 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1581f299/Allura/allura/command/base.py
----------------------------------------------------------------------
diff --git a/Allura/allura/command/base.py b/Allura/allura/command/base.py
index 536159d..38bb0d5 100644
--- a/Allura/allura/command/base.py
+++ b/Allura/allura/command/base.py
@@ -20,7 +20,6 @@ import sys
 import logging
 import shlex
 from multiprocessing import Process
-from pkg_resources import iter_entry_points
 
 import pylons
 from paste.script import command
@@ -31,6 +30,7 @@ import activitystream
 import ming
 from allura.config.environment import load_environment
 from allura.lib.decorators import task
+from allura.lib.helpers import iter_entry_points
 
 log = None
 
@@ -117,4 +117,3 @@ class Command(command.Command):
 
     def teardown_globals(self):
         self.registry.cleanup()
-

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1581f299/Allura/allura/config/resources.py
----------------------------------------------------------------------
diff --git a/Allura/allura/config/resources.py b/Allura/allura/config/resources.py
index 9122687..6e231e4 100644
--- a/Allura/allura/config/resources.py
+++ b/Allura/allura/config/resources.py
@@ -20,6 +20,8 @@ import logging
 
 import pkg_resources
 
+from allura.lib.helpers import iter_entry_points
+
 log = logging.getLogger(__name__)
 
 def register_ew_resources(manager):
@@ -29,7 +31,7 @@ def register_ew_resources(manager):
         'css', pkg_resources.resource_filename('allura', 'lib/widgets/resources/css'))
     manager.register_directory(
         'allura', pkg_resources.resource_filename('allura', 'public/nf'))
-    for ep in pkg_resources.iter_entry_points('allura'):
+    for ep in iter_entry_points('allura'):
         try:
             manager.register_directory(
                 'tool/%s' % ep.name.lower(),
@@ -39,7 +41,7 @@ def register_ew_resources(manager):
         except ImportError:
             log.warning('Cannot import entry point %s', ep)
             raise
-    for ep in pkg_resources.iter_entry_points('allura.theme'):
+    for ep in iter_entry_points('allura.theme'):
         try:
             theme = ep.load()
             theme.register_ew_resources(manager, ep.name)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1581f299/Allura/allura/controllers/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index 5f293a6..9914dc9 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -20,7 +20,6 @@ import logging
 from datetime import datetime, timedelta
 from urllib import unquote
 from itertools import chain, islice
-from pkg_resources import iter_entry_points
 
 from bson import ObjectId
 from tg import expose, flash, redirect, validate, request, response, config
@@ -38,6 +37,7 @@ from allura import model as M
 from allura.app import SitemapEntry
 from allura.lib.base import WsgiDispatchController
 from allura.lib import helpers as h
+from allura.lib.helpers import iter_entry_points
 from allura.lib import utils
 from allura.lib.decorators import require_post
 from allura.controllers.error import ErrorController
@@ -310,7 +310,7 @@ class ProjectController(FeedController):
         for s in c.project.grouped_navbar_entries():
             entry = dict(name=s.label, url=s.url, icon=s.ui_icon, tool_name=s.tool_name)
             if s.children:
-                entry['children'] = [dict(name=child.label, url=child.url, icon=child.ui_icon, tool_name=child.tool_name) 
+                entry['children'] = [dict(name=child.label, url=child.url, icon=child.ui_icon, tool_name=child.tool_name)
                                     for child in s.children]
             menu.append(entry)
         return dict(menu=menu)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1581f299/Allura/allura/ext/admin/admin_main.py
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/admin/admin_main.py b/Allura/allura/ext/admin/admin_main.py
index 22bd228..314c3a9 100644
--- a/Allura/allura/ext/admin/admin_main.py
+++ b/Allura/allura/ext/admin/admin_main.py
@@ -292,7 +292,7 @@ class ProjectAdminController(BaseController):
                 '<input name="source_url">'
                 '<input type="submit">'
                 '</form>')
-        for ep in pkg_resources.iter_entry_points('allura', repo_type):
+        for ep in h.iter_entry_points('allura', repo_type):
             break
         if ep is None or source_url is None:
             raise exc.HTTPNotFound

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1581f299/Allura/allura/lib/app_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index 7f45f69..276af63 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -178,7 +178,7 @@ class Globals(object):
         # Cache some loaded entry points
         def _cache_eps(section_name, dict_cls=dict):
             d = dict_cls()
-            for ep in pkg_resources.iter_entry_points(section_name):
+            for ep in h.iter_entry_points(section_name):
                 value = ep.load()
                 d[ep.name] = value
             return d

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1581f299/Allura/allura/lib/custom_middleware.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/custom_middleware.py b/Allura/allura/lib/custom_middleware.py
index 4458c48..d4652ab 100644
--- a/Allura/allura/lib/custom_middleware.py
+++ b/Allura/allura/lib/custom_middleware.py
@@ -35,7 +35,7 @@ import allura.model.repo
 log = logging.getLogger(__name__)
 
 
-tool_entry_points = list(pkg_resources.iter_entry_points('allura'))
+tool_entry_points = list(h.iter_entry_points('allura'))
 
 class StaticFilesMiddleware(object):
     '''Custom static file middleware
@@ -169,7 +169,7 @@ class SSLMiddleware(object):
         if not resp:
             resp = self.app
         return resp(environ, start_response)
-    
+
 class AlluraTimerMiddleware(TimerMiddleware):
     def timers(self):
         import genshi

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1581f299/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index b7b0060..3715de6 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -49,7 +49,7 @@ from tg.decorators import before_validate
 from formencode.variabledecode import variable_decode
 import formencode
 from jinja2 import Markup
-from paste.deploy.converters import asbool
+from paste.deploy.converters import asbool, aslist
 
 from webhelpers import date, feedgenerator, html, number, misc, text
 
@@ -984,3 +984,13 @@ def plain2markdown(text, preserve_multiple_spaces=False, has_html_entities=False
     text = re_angle_bracket_open.sub('&lt;', text)
     text = re_angle_bracket_close.sub('&gt;', text)
     return text
+
+
+def iter_entry_points(group, *a, **kw):
+    '''
+    yield entry points that have not been disabled in the config
+    '''
+    disabled = aslist(tg.config.get('disable_entry_points.' + group), sep=',')
+    for ep in pkg_resources.iter_entry_points(group, *a, **kw):
+        if ep.name not in disabled:
+            yield ep

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1581f299/Allura/allura/lib/package_path_loader.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/package_path_loader.py b/Allura/allura/lib/package_path_loader.py
index 9bee4c4..8272acf 100644
--- a/Allura/allura/lib/package_path_loader.py
+++ b/Allura/allura/lib/package_path_loader.py
@@ -124,12 +124,11 @@ The positioners are:
 """
 import pkg_resources
 import os
-from collections import defaultdict
 
 import jinja2
 from ming.utils import LazyProperty
 
-from allura.lib.helpers import topological_sort
+from allura.lib.helpers import topological_sort, iter_entry_points
 
 
 class PackagePathLoader(jinja2.BaseLoader):
@@ -163,7 +162,7 @@ class PackagePathLoader(jinja2.BaseLoader):
         paths = self.default_paths[:]  # copy default_paths
         paths[-1:0] = [  # insert all eps just before last item, by default
                 [ep.name, pkg_resources.resource_filename(ep.module_name, "")]
-                for ep in pkg_resources.iter_entry_points(self.override_entrypoint)
+                for ep in iter_entry_points(self.override_entrypoint)
             ]
         return paths
 
@@ -190,7 +189,7 @@ class PackagePathLoader(jinja2.BaseLoader):
         """
         order_rules = []
         replacement_rules = {}
-        for ep in pkg_resources.iter_entry_points(self.override_entrypoint):
+        for ep in iter_entry_points(self.override_entrypoint):
             for rule in getattr(ep.load(), 'template_path_rules', []):
                 if rule[0] == '>':
                     order_rules.append((ep.name, rule[1]))

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1581f299/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index fb58ce9..b048ce6 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -28,7 +28,6 @@ from hashlib import sha256
 import uuid
 from pytz import timezone
 from datetime import timedelta, date, datetime, time
-from pkg_resources import iter_entry_points
 
 import iso8601
 import pymongo

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1581f299/Allura/docs/extending.rst
----------------------------------------------------------------------
diff --git a/Allura/docs/extending.rst b/Allura/docs/extending.rst
index a430202..6a6abe0 100644
--- a/Allura/docs/extending.rst
+++ b/Allura/docs/extending.rst
@@ -37,7 +37,15 @@ The available extension points for Allura are:
 
 A listing of available 3rd-party extensions is at https://sourceforge.net/p/allura/wiki/Extensions/
 
-Other entry points are used to provider ``paster`` commands and ``easy_widget`` configuration.
+To disable any Allura entry point, simply add an entry in your ``.ini`` config file
+with names and values corresponding to entry points defined in any ``setup.py`` file.
+For example if you have ForgeImporter set up, but want to disable the google code importers::
+
+    disable_entry_points.allura.project_importers = google-code
+    disable_entry_points.allura.importers = google-code-tracker, google-code-repo
+
+Other entry points are used to provide ``paster`` commands and ``easy_widget`` configuration,
+which are not part of Allura but are used by Allura.
 
 
 Event Handlers

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1581f299/ForgeImporters/forgeimporters/base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index bdff43b..7f25e69 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -20,8 +20,6 @@ import urllib
 import urllib2
 from collections import defaultdict
 
-from pkg_resources import iter_entry_points
-
 from BeautifulSoup import BeautifulSoup
 from tg import expose, validate, flash, redirect, config
 from tg.decorators import with_trailing_slash
@@ -176,7 +174,7 @@ class ProjectImporter(BaseController):
         as this project importer.
         """
         tools = {}
-        for ep in iter_entry_points('allura.importers'):
+        for ep in h.iter_entry_points('allura.importers'):
             epv = ep.load()
             if epv.source == self.source:
                 tools[ep.name] = epv()
@@ -289,7 +287,7 @@ class ToolImporter(object):
         """
         Return a ToolImporter subclass instance given its entry-point name.
         """
-        for ep in iter_entry_points('allura.importers', name):
+        for ep in h.iter_entry_points('allura.importers', name):
             return ep.load()()
 
     @staticmethod
@@ -298,7 +296,7 @@ class ToolImporter(object):
         Return a ToolImporter subclass instance given its target_app class.
         """
         importers = {}
-        for ep in iter_entry_points('allura.importers'):
+        for ep in h.iter_entry_points('allura.importers'):
             importer = ep.load()
             if app in aslist(importer.target_app):
                 importers[ep.name] = importer()
@@ -370,7 +368,7 @@ class ProjectToolsImportController(object):
     def index(self, *a, **kw):
         importer_matrix = defaultdict(dict)
         tools_with_importers = set()
-        for ep in iter_entry_points('allura.importers'):
+        for ep in h.iter_entry_points('allura.importers'):
             importer = ep.load()
             for tool in aslist(importer.target_app):
                 tools_with_importers.add(tool.tool_label)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1581f299/ForgeImporters/forgeimporters/tests/test_base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/test_base.py b/ForgeImporters/forgeimporters/tests/test_base.py
index f1c93ad..92fb0cc 100644
--- a/ForgeImporters/forgeimporters/tests/test_base.py
+++ b/ForgeImporters/forgeimporters/tests/test_base.py
@@ -66,7 +66,7 @@ def ep(name, source=None, importer=None, **kw):
 
 
 class TestProjectImporter(TestCase):
-    @mock.patch.object(base, 'iter_entry_points')
+    @mock.patch.object(base.h, 'iter_entry_points')
     def test_tool_importers(self, iep):
         eps = iep.return_value = [ep('ep1', 'foo'), ep('ep2', 'bar'), ep('ep3', 'foo')]
         pi = base.ProjectImporter(mock.Mock(name='neighborhood'))
@@ -100,7 +100,7 @@ class TI3(base.ToolImporter):
 class TestToolImporter(TestCase):
 
 
-    @mock.patch.object(base, 'iter_entry_points')
+    @mock.patch.object(base.h, 'iter_entry_points')
     def test_by_name(self, iep):
         eps = iep.return_value = [ep('my-name', 'my-source')]
         importer = base.ToolImporter.by_name('my-name')
@@ -113,7 +113,7 @@ class TestToolImporter(TestCase):
         iep.assert_called_once_with('allura.importers', 'other-name')
         self.assertEqual(importer, None)
 
-    @mock.patch.object(base, 'iter_entry_points')
+    @mock.patch.object(base.h, 'iter_entry_points')
     def test_by_app(self, iep):
         eps = iep.return_value = [
                 ep('importer1', importer=TI1),
@@ -190,7 +190,7 @@ class TestProjectToolsImportController(TestController):
 
     def test_pages(self):
         admin_page = self.app.get('/admin/')
-        with mock.patch.object(base, 'iter_entry_points') as iep:
+        with mock.patch.object(base.h, 'iter_entry_points') as iep:
             iep.return_value = [
                 ep('importer1', importer=TI1),
                 ep('importer2', importer=TI2),

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1581f299/scripts/rethumb.py
----------------------------------------------------------------------
diff --git a/scripts/rethumb.py b/scripts/rethumb.py
index 5f753ff..6ee190a 100644
--- a/scripts/rethumb.py
+++ b/scripts/rethumb.py
@@ -18,14 +18,16 @@
 import sys
 import time
 
-import pkg_resources
 import PIL
 import tg
 from pylons import tmpl_context as c
 from paste.deploy.converters import asint
 
 from ming.orm import mapper, ThreadLocalORMSession, session, state, Mapper
+
 from allura.command import base
+from allura.lib.helpers import iter_entry_points
+
 import forgetracker.model
 
 
@@ -109,7 +111,7 @@ class RethumbCommand(base.Command):
                 self.process_att_of_type(M.DiscussionAttachment, {'app_config_id': app._id, 'discussion_id': {'$ne': None}})
 
                 # Otherwise, we'll take attachment classes belonging to app's package
-                ep = pkg_resources.iter_entry_points('allura', app.tool_name).next()
+                ep = iter_entry_points('allura', app.tool_name).next()
                 app_package = ep.module_name.split('.', 1)[0]
                 if app_package == 'allura':
                     # Apps in allura known to not define own attachment types


[05/13] git commit: [#6482] simpler logic to build matrix of importers (thanks Cory)

Posted by tv...@apache.org.
[#6482] simpler logic to build matrix of importers (thanks Cory)


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/ec9c7cf0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/ec9c7cf0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/ec9c7cf0

Branch: refs/heads/master
Commit: ec9c7cf0004f44b1b042aef9b83d22235d92da40
Parents: 7f179dc
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Tue Aug 13 21:12:37 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Tue Aug 27 17:24:58 2013 +0000

----------------------------------------------------------------------
 ForgeImporters/forgeimporters/base.py           | 27 ++++----------------
 .../forgeimporters/templates/list_all.html      | 12 ++++-----
 2 files changed, 11 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ec9c7cf0/ForgeImporters/forgeimporters/base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index e957b1a..e80235e 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -360,33 +360,16 @@ class ProjectToolsImportController(object):
     @with_trailing_slash
     @expose('jinja:forgeimporters:templates/list_all.html')
     def index(self, *a, **kw):
-        # make dictionaries of both axis
-        importers_by_source = defaultdict(dict)
-        importers_by_tool = defaultdict(dict)
+        importer_matrix = defaultdict(dict)
+        tools_with_importers = set()
         for ep in iter_entry_points('allura.importers'):
             importer = ep.load()
-            importers_by_source[importer.source][ep.name] = importer
             for tool in aslist(importer.target_app):
-                importers_by_tool[tool][ep.name] = importer
-
-        relevant_tools = sorted(importers_by_tool.keys(), key=lambda t: t.tool_label)
-
-        # build a full matrix including empty spots
-        importer_matrix = dict() # source -> [importer names]
-        for source, src_importers in importers_by_source.iteritems():
-            row = list()
-            for tool in relevant_tools:
-                for ep_name, importer in src_importers.iteritems():
-                    if tool in aslist(importer.target_app):
-                        row.append(ep_name)
-                        break
-                else:
-                    row.append(None)
-            importer_matrix[source] = row
-
+                tools_with_importers.add(tool.tool_label)
+                importer_matrix[importer.source][tool.tool_label] = ep.name
         return {
-            'tools': relevant_tools,
             'importer_matrix': importer_matrix,
+            'tools': tools_with_importers,
         }
 
     @expose()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ec9c7cf0/ForgeImporters/forgeimporters/templates/list_all.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/templates/list_all.html b/ForgeImporters/forgeimporters/templates/list_all.html
index b91e0df..b4c0a06 100644
--- a/ForgeImporters/forgeimporters/templates/list_all.html
+++ b/ForgeImporters/forgeimporters/templates/list_all.html
@@ -31,18 +31,18 @@
     <thead>
     <tr>
         <th></th>
-        {% for tool in tools %}
-            <th>{{tool.tool_label}}</th>
+        {% for tool in tools|sort %}
+            <th>{{tool}}</th>
         {% endfor %}
     </tr>
     </thead>
-    {% for source, importers in importer_matrix|dictsort %}
+    {% for source in importer_matrix.keys()|sort  %}
         <tr>
         <td><strong>{{ source }}</strong></td>
-        {% for importer_name in importers %}
+        {% for tool in tools|sort %}
             <td>
-                {% if importer_name %}
-                <a href="{{importer_name}}">Import</a>
+                {% if importer_matrix[source].get(tool) %}
+                <a href="{{ importer_matrix[source][tool] }}">Import</a>
                 {% endif %}
             </td>
         {% endfor %}


[10/13] git commit: [#6526] Set c.project before calling MountPointValidator

Posted by tv...@apache.org.
[#6526] Set c.project before calling MountPointValidator

Signed-off-by: Tim Van Steenburgh <tv...@gmail.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/eceab844
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/eceab844
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/eceab844

Branch: refs/heads/master
Commit: eceab844fdd664eff62b1a64380bce01a0767d07
Parents: 9704ca5
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Wed Aug 28 16:08:34 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Wed Aug 28 16:08:34 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/validators.py | 6 ++----
 Allura/allura/model/project.py  | 9 +++++----
 2 files changed, 7 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/eceab844/Allura/allura/lib/validators.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/validators.py b/Allura/allura/lib/validators.py
index 9d15429..3295bb0 100644
--- a/Allura/allura/lib/validators.py
+++ b/Allura/allura/lib/validators.py
@@ -90,8 +90,7 @@ class MountPointValidator(fev.UnicodeString):
         if mount_point in self.reserved_mount_points:
             raise fe.Invalid('Mount point "%s" is reserved' % mount_point,
                     value, state)
-        if (getattr(c, 'project', None) and
-                c.project.app_instance(mount_point) is not None):
+        if c.project and c.project.app_instance(mount_point) is not None:
             raise fe.Invalid('Mount point "%s" is already in use' % mount_point,
                     value, state)
         return mount_point
@@ -100,8 +99,7 @@ class MountPointValidator(fev.UnicodeString):
         base_mount_point = mount_point = self.app_class.default_mount_point
         i = 0
         while True:
-            if (not getattr(c, 'project', None) or
-                    c.project.app_instance(mount_point) is None):
+            if not c.project or c.project.app_instance(mount_point) is None:
                 return mount_point
             mount_point = base_mount_point + '-%d' % i
             i += 1

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/eceab844/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index 983ef66..ec39157 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -600,10 +600,11 @@ class Project(MappedClass, ActivityNode, ActivityObject):
 
     def install_app(self, ep_name, mount_point=None, mount_label=None, ordinal=None, **override_options):
         App = g.entry_points['tool'][ep_name]
-        try:
-            mount_point = v.MountPointValidator(App).to_python(mount_point)
-        except fe.Invalid as e:
-            raise exceptions.ToolError(str(e))
+        with h.push_config(c, project=self):
+            try:
+                mount_point = v.MountPointValidator(App).to_python(mount_point)
+            except fe.Invalid as e:
+                raise exceptions.ToolError(str(e))
         if ordinal is None:
             ordinal = int(self.ordered_mounts(include_hidden=True)[-1]['ordinal']) + 1
         options = App.default_options()


[08/13] git commit: [#6526] Better label on submit button

Posted by tv...@apache.org.
[#6526] Better label on submit button

Signed-off-by: Tim Van Steenburgh <tv...@gmail.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/90651671
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/90651671
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/90651671

Branch: refs/heads/master
Commit: 906516719ecc8b3a6c10c4a253a443d7367c0dbd
Parents: a4dc01b
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Wed Aug 28 14:34:10 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Wed Aug 28 14:34:10 2013 +0000

----------------------------------------------------------------------
 ForgeImporters/forgeimporters/templates/importer_base.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/90651671/ForgeImporters/forgeimporters/templates/importer_base.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/templates/importer_base.html b/ForgeImporters/forgeimporters/templates/importer_base.html
index 4bdfe0f..7a25543 100644
--- a/ForgeImporters/forgeimporters/templates/importer_base.html
+++ b/ForgeImporters/forgeimporters/templates/importer_base.html
@@ -75,6 +75,6 @@
       {{ error('mount_point') }}
   </div>
 
-  <input type="submit" />
+  <input type="submit" value="Import"/>
 </form>
 {% endblock %}


[11/13] git commit: [#6526] bump Google Code & Trac Wiki importer versions for their changes

Posted by tv...@apache.org.
[#6526] bump Google Code & Trac Wiki importer versions for their changes


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/10cb90c7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/10cb90c7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/10cb90c7

Branch: refs/heads/master
Commit: 10cb90c712a79fb8a64d5f7dbcc0aaa5b7132b04
Parents: eceab84
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Wed Aug 28 17:08:01 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Wed Aug 28 17:08:01 2013 +0000

----------------------------------------------------------------------
 requirements-sf.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/10cb90c7/requirements-sf.txt
----------------------------------------------------------------------
diff --git a/requirements-sf.txt b/requirements-sf.txt
index a77c839..4e00d83 100644
--- a/requirements-sf.txt
+++ b/requirements-sf.txt
@@ -6,7 +6,7 @@ kombu==1.0.4
 coverage==3.5a1-20110413
 ForgeHg==0.1.15
 ForgePastebin==0.2.7
-GoogleCodeWikiImporter==0.2.0
+GoogleCodeWikiImporter==0.3.0
 mechanize==0.2.4
 mercurial==1.4.3
 MySQL-python==1.2.3c1
@@ -20,7 +20,7 @@ wsgipreload==1.2
 pyzmq==2.1.7
 html2text==3.200.3dev-20121112
 PyMollom==0.1
-TracWikiImporter==0.1.0
+TracWikiImporter==0.2.0
 
 # use version built from https://github.com/johnsca/GitPython/commits/tv/6000
 # for unmerged fixes for [#5411], [#6000], and [#6078]


[07/13] git commit: [#6526] Fix MountPointValidator to provide default value

Posted by tv...@apache.org.
[#6526] Fix MountPointValidator to provide default value

Signed-off-by: Tim Van Steenburgh <tv...@gmail.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/a4dc01b3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/a4dc01b3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/a4dc01b3

Branch: refs/heads/master
Commit: a4dc01b395929b0ba05a14f1a37e590ebdf42a6f
Parents: 6ff3125
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Wed Aug 28 14:30:28 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Wed Aug 28 14:30:28 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/validators.py        | 23 ++++++-----
 Allura/allura/tests/test_validators.py | 61 +++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a4dc01b3/Allura/allura/lib/validators.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/validators.py b/Allura/allura/lib/validators.py
index fa82d32..3295bb0 100644
--- a/Allura/allura/lib/validators.py
+++ b/Allura/allura/lib/validators.py
@@ -19,6 +19,7 @@ import json
 from bson import ObjectId
 import formencode as fe
 from formencode import validators as fev
+from pylons import tmpl_context as c
 from . import helpers as h
 from datetime import datetime
 
@@ -74,20 +75,13 @@ class MaxBytesValidator(fev.FancyValidator):
 
 class MountPointValidator(fev.UnicodeString):
     def __init__(self, app_class,
-            reserved_mount_points=('feed', 'index', 'icon', '_nav.json')):
-        super(self.__class__, self).__init__()
+            reserved_mount_points=('feed', 'index', 'icon', '_nav.json'), **kw):
+        super(self.__class__, self).__init__(**kw)
         self.app_class = app_class
         self.reserved_mount_points = reserved_mount_points
 
     def _to_python(self, value, state):
-        from pylons import tmpl_context as c
-        project = state.project if hasattr(state, 'project') else c.project
         mount_point, App = value, self.app_class
-        if not mount_point:
-            base_mount_point = mount_point = App.default_mount_point
-            for x in range(10):
-                if project.app_instance(mount_point) is None: break
-                mount_point = base_mount_point + '-%d' % x
         if not App.relaxed_mount_points:
             mount_point = mount_point.lower()
         if not App.validate_mount_point(mount_point):
@@ -96,11 +90,20 @@ class MountPointValidator(fev.UnicodeString):
         if mount_point in self.reserved_mount_points:
             raise fe.Invalid('Mount point "%s" is reserved' % mount_point,
                     value, state)
-        if project.app_instance(mount_point) is not None:
+        if c.project and c.project.app_instance(mount_point) is not None:
             raise fe.Invalid('Mount point "%s" is already in use' % mount_point,
                     value, state)
         return mount_point
 
+    def empty_value(self, value):
+        base_mount_point = mount_point = self.app_class.default_mount_point
+        i = 0
+        while True:
+            if not c.project or c.project.app_instance(mount_point) is None:
+                return mount_point
+            mount_point = base_mount_point + '-%d' % i
+            i += 1
+
 class TaskValidator(fev.FancyValidator):
     def _to_python(self, value, state):
         try:

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a4dc01b3/Allura/allura/tests/test_validators.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_validators.py b/Allura/allura/tests/test_validators.py
index b0d165c..26779ce 100644
--- a/Allura/allura/tests/test_validators.py
+++ b/Allura/allura/tests/test_validators.py
@@ -17,6 +17,7 @@
 
 import unittest
 import formencode as fe
+from mock import Mock, patch
 
 from allura import model as M
 from allura.lib import validators as v
@@ -92,6 +93,66 @@ class TestUserValidator(unittest.TestCase):
         self.assertEqual(str(cm.exception), "Invalid username")
 
 
+class TestMountPointValidator(unittest.TestCase):
+
+    @patch('allura.lib.validators.c')
+    def test_valid(self, c):
+        App = Mock()
+        App.relaxed_mount_points = False
+        App.validate_mount_point.return_value = True
+        c.project.app_instance.return_value = None
+        val = v.MountPointValidator(App)
+        self.assertEqual('mymount', val.to_python('Mymount'))
+
+    @patch('allura.lib.validators.c')
+    def test_invalid(self, c):
+        App = Mock()
+        App.relaxed_mount_points = False
+        App.validate_mount_point.return_value = False
+        c.project.app_instance.return_value = False
+        val = v.MountPointValidator(App)
+        with self.assertRaises(fe.Invalid):
+            val.to_python('mymount')
+
+    @patch('allura.lib.validators.c')
+    def test_relaxed_mount_points(self, c):
+        App = Mock()
+        App.relaxed_mount_points = True
+        App.validate_mount_point.return_value = True
+        c.project.app_instance.return_value = None
+        val = v.MountPointValidator(App)
+        self.assertEqual('Mymount', val.to_python('Mymount'))
+
+    @patch('allura.lib.validators.c')
+    def test_in_use(self, c):
+        App = Mock()
+        App.relaxed_mount_points = False
+        App.validate_mount_point.return_value = True
+        c.project.app_instance.return_value = True
+        val = v.MountPointValidator(App)
+        with self.assertRaises(fe.Invalid):
+            val.to_python('mymount')
+
+    @patch('allura.lib.validators.c')
+    def test_reserved(self, c):
+        App = Mock()
+        App.relaxed_mount_points = False
+        App.validate_mount_point.return_value = True
+        c.project.app_instance.return_value = False
+        val = v.MountPointValidator(App)
+        with self.assertRaises(fe.Invalid):
+            val.to_python('feed')
+
+    @patch('allura.lib.validators.c')
+    def test_empty(self, c):
+        App = Mock()
+        App.default_mount_point = 'wiki'
+        c.project.app_instance.side_effect = lambda mp: None if mp != 'wiki' else True
+        val = v.MountPointValidator(App)
+        self.assertEqual('wiki-0', val.to_python(''))
+        self.assertEqual('wiki-0', val.to_python(None))
+
+
 class TestTaskValidator(unittest.TestCase):
     val = v.TaskValidator
 


[06/13] git commit: [#6482] add a test for the importer admin page

Posted by tv...@apache.org.
[#6482] add a test for the importer admin page


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/7f179dca
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/7f179dca
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/7f179dca

Branch: refs/heads/master
Commit: 7f179dca16b4a37936a1d3427aa18db130a3292a
Parents: b7fb5f2
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Tue Aug 13 20:38:30 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Tue Aug 27 17:24:58 2013 +0000

----------------------------------------------------------------------
 ForgeImporters/forgeimporters/base.py           |  4 +-
 .../forgeimporters/tests/test_base.py           | 74 ++++++++++++++------
 2 files changed, 56 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7f179dca/ForgeImporters/forgeimporters/base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index c6cdf4a..e957b1a 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -404,5 +404,5 @@ class ImportAdminExtension(AdminExtension):
 
     def update_project_sidebar_menu(self, sidebar_links):
         base_url = c.project.url() + 'admin/ext/'
-        link = SitemapEntry('Import', base_url+'import')
-        sidebar_links.append(link)
+        link = SitemapEntry('Import', base_url+'import/')
+        sidebar_links.append(link)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/7f179dca/ForgeImporters/forgeimporters/tests/test_base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/test_base.py b/ForgeImporters/forgeimporters/tests/test_base.py
index 57ed227..f1c93ad 100644
--- a/ForgeImporters/forgeimporters/tests/test_base.py
+++ b/ForgeImporters/forgeimporters/tests/test_base.py
@@ -19,6 +19,10 @@ from unittest import TestCase
 
 from formencode import Invalid
 import mock
+from tg import expose
+from nose.tools import assert_equal
+
+from alluratest.controller import TestController
 
 from .. import base
 
@@ -76,17 +80,25 @@ TA1 = mock.Mock(tool_label='foo', tool_description='foo_desc')
 TA2 = mock.Mock(tool_label='qux', tool_description='qux_desc')
 TA3 = mock.Mock(tool_label='baz', tool_description='baz_desc')
 
-class TestToolImporter(TestCase):
-    class TI1(base.ToolImporter):
-        target_app = TA1
+class TI1Controller(object):
+    @expose()
+    def index(self, *a, **kw):
+        return 'test importer 1 controller webpage'
+
+class TI1(base.ToolImporter):
+    target_app = TA1
+    controller = TI1Controller
+
+class TI2(base.ToolImporter):
+    target_app = TA2
+    tool_label = 'bar'
+    tool_description = 'bar_desc'
+
+class TI3(base.ToolImporter):
+    target_app = [TA2, TA2]
 
-    class TI2(base.ToolImporter):
-        target_app = TA2
-        tool_label = 'bar'
-        tool_description = 'bar_desc'
+class TestToolImporter(TestCase):
 
-    class TI3(base.ToolImporter):
-        target_app = [TA2, TA2]
 
     @mock.patch.object(base, 'iter_entry_points')
     def test_by_name(self, iep):
@@ -104,27 +116,27 @@ class TestToolImporter(TestCase):
     @mock.patch.object(base, 'iter_entry_points')
     def test_by_app(self, iep):
         eps = iep.return_value = [
-                ep('importer1', importer=self.TI1),
-                ep('importer2', importer=self.TI2),
-                ep('importer3', importer=self.TI3),
+                ep('importer1', importer=TI1),
+                ep('importer2', importer=TI2),
+                ep('importer3', importer=TI3),
             ]
         importers = base.ToolImporter.by_app(TA2)
         self.assertEqual(set(importers.keys()), set([
                 'importer2',
                 'importer3',
             ]))
-        self.assertIsInstance(importers['importer2'], self.TI2)
-        self.assertIsInstance(importers['importer3'], self.TI3)
+        self.assertIsInstance(importers['importer2'], TI2)
+        self.assertIsInstance(importers['importer3'], TI3)
 
     def test_tool_label(self):
-        self.assertEqual(self.TI1().tool_label, 'foo')
-        self.assertEqual(self.TI2().tool_label, 'bar')
-        self.assertEqual(self.TI3().tool_label, 'qux')
+        self.assertEqual(TI1().tool_label, 'foo')
+        self.assertEqual(TI2().tool_label, 'bar')
+        self.assertEqual(TI3().tool_label, 'qux')
 
     def test_tool_description(self):
-        self.assertEqual(self.TI1().tool_description, 'foo_desc')
-        self.assertEqual(self.TI2().tool_description, 'bar_desc')
-        self.assertEqual(self.TI3().tool_description, 'qux_desc')
+        self.assertEqual(TI1().tool_description, 'foo_desc')
+        self.assertEqual(TI2().tool_description, 'bar_desc')
+        self.assertEqual(TI3().tool_description, 'qux_desc')
 
 
 class TestToolsValidator(TestCase):
@@ -172,3 +184,25 @@ class TestToolsValidator(TestCase):
                 mock.call('value1'),
                 mock.call('value2'),
             ])
+
+
+class TestProjectToolsImportController(TestController):
+
+    def test_pages(self):
+        admin_page = self.app.get('/admin/')
+        with mock.patch.object(base, 'iter_entry_points') as iep:
+            iep.return_value = [
+                ep('importer1', importer=TI1),
+                ep('importer2', importer=TI2),
+                ep('importer3', importer=TI3),
+            ]
+            import_main_page = admin_page.click('Import')
+        url = import_main_page.environ['PATH_INFO']
+        assert url.endswith('/admin/ext/import/'), url
+
+        with mock.patch.object(base.ToolImporter, 'by_name') as by_name:
+            by_name.return_value = TI1
+            import1_page = import_main_page.click('Import', href=r'importer1$')
+        url = import1_page.environ['PATH_INFO']
+        assert url.endswith('/admin/ext/import/importer1'), url
+        assert_equal(import1_page.body, 'test importer 1 controller webpage')


[02/13] git commit: [#6482] change page to show importers in a grid

Posted by tv...@apache.org.
[#6482] change page to show importers in a grid


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/b7fb5f2d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/b7fb5f2d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/b7fb5f2d

Branch: refs/heads/master
Commit: b7fb5f2dd43636783c58c6f5d03b4fbe0a216820
Parents: f705a17
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Tue Aug 13 19:20:11 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Tue Aug 27 17:24:58 2013 +0000

----------------------------------------------------------------------
 ForgeImporters/forgeimporters/base.py           | 31 +++++++++--
 .../forgeimporters/templates/list_all.html      | 58 ++++++++------------
 2 files changed, 51 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/b7fb5f2d/ForgeImporters/forgeimporters/base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index 620097e..c6cdf4a 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -18,6 +18,7 @@
 import logging
 import urllib
 import urllib2
+from collections import defaultdict
 
 from pkg_resources import iter_entry_points
 
@@ -359,11 +360,33 @@ class ProjectToolsImportController(object):
     @with_trailing_slash
     @expose('jinja:forgeimporters:templates/list_all.html')
     def index(self, *a, **kw):
-        importers = {}
-        for app_name, app in g.entry_points['tool'].iteritems():
-            importers[app] = ToolImporter.by_app(app)
+        # make dictionaries of both axis
+        importers_by_source = defaultdict(dict)
+        importers_by_tool = defaultdict(dict)
+        for ep in iter_entry_points('allura.importers'):
+            importer = ep.load()
+            importers_by_source[importer.source][ep.name] = importer
+            for tool in aslist(importer.target_app):
+                importers_by_tool[tool][ep.name] = importer
+
+        relevant_tools = sorted(importers_by_tool.keys(), key=lambda t: t.tool_label)
+
+        # build a full matrix including empty spots
+        importer_matrix = dict() # source -> [importer names]
+        for source, src_importers in importers_by_source.iteritems():
+            row = list()
+            for tool in relevant_tools:
+                for ep_name, importer in src_importers.iteritems():
+                    if tool in aslist(importer.target_app):
+                        row.append(ep_name)
+                        break
+                else:
+                    row.append(None)
+            importer_matrix[source] = row
+
         return {
-            'importers': importers
+            'tools': relevant_tools,
+            'importer_matrix': importer_matrix,
         }
 
     @expose()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/b7fb5f2d/ForgeImporters/forgeimporters/templates/list_all.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/templates/list_all.html b/ForgeImporters/forgeimporters/templates/list_all.html
index 58c9f34..b91e0df 100644
--- a/ForgeImporters/forgeimporters/templates/list_all.html
+++ b/ForgeImporters/forgeimporters/templates/list_all.html
@@ -21,42 +21,32 @@
 
 {% block title %}{{c.project.name}} / Import{% endblock %}
 
-{% block header %}Import from external sources{% endblock %}
-
-{% block extra_css %}
-<style type="text/css">
-    .tool {
-        margin-bottom: 3em;
-    }
-    .tool img {
-        float: left;
-        margin: 0 1em;
-    }
-    .importer .descr {
-        margin: 0 2em 1em 2em;
-    }
-</style>
-{% endblock %}
+{% block header %}Import{% endblock %}
 
 {% block content %}
-    {% for tool, tool_importers in importers.iteritems() %}
-        <div class="tool">
-        {% for importer_name, importer in tool_importers.iteritems() %}
-            {% if loop.first %}
-                <img src="{{ g.theme.app_icon_url(tool, 48) }}" alt="{{ tool.tool_label }} icon">
-                <h2>{{ tool.tool_label }}</h2>
-            {% endif %}
-            <div class="importer">
-                <a href="{{importer_name}}"><h3>
-                {{importer.source}}:
-                {{importer.tool_label}}
-                </h3>
-                </a>
-                <div class="descr">
-                {{importer.tool_description}}
-                </div>
-            </div>
+<p>
+    To import from one of these external sources into your project, just click on "Import" and fill out the form.
+</p>
+<table>
+    <thead>
+    <tr>
+        <th></th>
+        {% for tool in tools %}
+            <th>{{tool.tool_label}}</th>
+        {% endfor %}
+    </tr>
+    </thead>
+    {% for source, importers in importer_matrix|dictsort %}
+        <tr>
+        <td><strong>{{ source }}</strong></td>
+        {% for importer_name in importers %}
+            <td>
+                {% if importer_name %}
+                <a href="{{importer_name}}">Import</a>
+                {% endif %}
+            </td>
         {% endfor %}
-        </div>
+        </tr>
     {% endfor %}
+</table>
 {% endblock %}


[04/13] git commit: [#6526] Clean up individual tool importers

Posted by tv...@apache.org.
[#6526] Clean up individual tool importers

- Make forms look (slightly) better
- Add validation
- Kick off import as task

Signed-off-by: Tim Van Steenburgh <tv...@gmail.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/8378ac03
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/8378ac03
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/8378ac03

Branch: refs/heads/master
Commit: 8378ac032f3d92ea77d2756336641f45a9c71931
Parents: ec9c7cf
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Wed Aug 21 20:53:33 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Tue Aug 27 17:24:58 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/validators.py                 | 29 +++++++
 Allura/allura/model/project.py                  | 23 ++----
 ForgeImporters/forgeimporters/base.py           | 10 ++-
 .../forgeimporters/google/__init__.py           |  2 +-
 ForgeImporters/forgeimporters/google/code.py    | 62 +++++++++++++--
 .../google/templates/code/index.html            | 25 ++----
 .../google/templates/tracker/index.html         | 27 +++++++
 .../forgeimporters/google/tests/test_code.py    | 17 ++---
 ForgeImporters/forgeimporters/google/tracker.py | 62 ++++++++++++++-
 .../forgeimporters/templates/importer_base.html | 80 ++++++++++++++++++++
 .../forgeimporters/tests/google/test_tracker.py | 34 ++++++++-
 .../trac/templates/tickets/index.html           | 41 ++++------
 .../forgeimporters/trac/tests/test_tickets.py   | 20 ++---
 ForgeImporters/forgeimporters/trac/tickets.py   | 40 +++++++---
 14 files changed, 364 insertions(+), 108 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8378ac03/Allura/allura/lib/validators.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/validators.py b/Allura/allura/lib/validators.py
index 9b44d53..fa82d32 100644
--- a/Allura/allura/lib/validators.py
+++ b/Allura/allura/lib/validators.py
@@ -72,6 +72,35 @@ class MaxBytesValidator(fev.FancyValidator):
     def from_python(self, value, state):
         return h.really_unicode(value or '')
 
+class MountPointValidator(fev.UnicodeString):
+    def __init__(self, app_class,
+            reserved_mount_points=('feed', 'index', 'icon', '_nav.json')):
+        super(self.__class__, self).__init__()
+        self.app_class = app_class
+        self.reserved_mount_points = reserved_mount_points
+
+    def _to_python(self, value, state):
+        from pylons import tmpl_context as c
+        project = state.project if hasattr(state, 'project') else c.project
+        mount_point, App = value, self.app_class
+        if not mount_point:
+            base_mount_point = mount_point = App.default_mount_point
+            for x in range(10):
+                if project.app_instance(mount_point) is None: break
+                mount_point = base_mount_point + '-%d' % x
+        if not App.relaxed_mount_points:
+            mount_point = mount_point.lower()
+        if not App.validate_mount_point(mount_point):
+            raise fe.Invalid('Mount point "%s" is invalid' % mount_point,
+                    value, state)
+        if mount_point in self.reserved_mount_points:
+            raise fe.Invalid('Mount point "%s" is reserved' % mount_point,
+                    value, state)
+        if project.app_instance(mount_point) is not None:
+            raise fe.Invalid('Mount point "%s" is already in use' % mount_point,
+                    value, state)
+        return mount_point
+
 class TaskValidator(fev.FancyValidator):
     def _to_python(self, value, state):
         try:

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8378ac03/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index ebccb3d..983ef66 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -26,6 +26,7 @@ from tg import config
 from pylons import tmpl_context as c, app_globals as g
 from pylons import request
 from paste.deploy.converters import asbool
+import formencode as fe
 
 from ming import schema as S
 from ming.utils import LazyProperty
@@ -38,6 +39,7 @@ from allura.lib import helpers as h
 from allura.lib import plugin
 from allura.lib import exceptions
 from allura.lib import security
+from allura.lib import validators as v
 from allura.lib.security import has_access
 
 from .session import main_orm_session
@@ -598,23 +600,10 @@ class Project(MappedClass, ActivityNode, ActivityObject):
 
     def install_app(self, ep_name, mount_point=None, mount_label=None, ordinal=None, **override_options):
         App = g.entry_points['tool'][ep_name]
-        if not mount_point:
-            base_mount_point = mount_point = App.default_mount_point
-            for x in range(10):
-                if self.app_instance(mount_point) is None: break
-                mount_point = base_mount_point + '-%d' % x
-        if not App.relaxed_mount_points:
-            mount_point = mount_point.lower()
-        if not App.validate_mount_point(mount_point):
-            raise exceptions.ToolError, 'Mount point "%s" is invalid' % mount_point
-        # HACK: reserved url components
-        if mount_point in ('feed', 'index', 'icon', '_nav.json'):
-            raise exceptions.ToolError, (
-                'Mount point "%s" is reserved' % mount_point)
-        if self.app_instance(mount_point) is not None:
-            raise exceptions.ToolError, (
-                'Mount point "%s" is already in use' % mount_point)
-        assert self.app_instance(mount_point) is None
+        try:
+            mount_point = v.MountPointValidator(App).to_python(mount_point)
+        except fe.Invalid as e:
+            raise exceptions.ToolError(str(e))
         if ordinal is None:
             ordinal = int(self.ordered_mounts(include_hidden=True)[-1]['ordinal']) + 1
         options = App.default_options()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8378ac03/ForgeImporters/forgeimporters/base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index e80235e..bdff43b 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -35,6 +35,7 @@ from allura.lib.security import require_access
 from allura.lib.plugin import ProjectRegistrationProvider, AdminExtension
 from allura.lib import helpers as h
 from allura.lib import exceptions
+from allura.lib import validators as v
 from allura.app import SitemapEntry
 
 from paste.deploy.converters import aslist
@@ -58,6 +59,13 @@ class ProjectImportForm(schema.Schema):
     project_name = fev.UnicodeString(not_empty=True, max=40)
 
 
+class ToolImportForm(schema.Schema):
+    def __init__(self, tool_class):
+        super(ToolImportForm, self).__init__()
+        self.add_field('mount_point', v.MountPointValidator(tool_class))
+    mount_label = fev.UnicodeString()
+
+
 @task(notifications_disabled=True)
 def import_tool(importer_name, project_name=None, mount_point=None, mount_label=None, **kw):
     importer = ToolImporter.by_name(importer_name)
@@ -388,4 +396,4 @@ class ImportAdminExtension(AdminExtension):
     def update_project_sidebar_menu(self, sidebar_links):
         base_url = c.project.url() + 'admin/ext/'
         link = SitemapEntry('Import', base_url+'import/')
-        sidebar_links.append(link)
\ No newline at end of file
+        sidebar_links.append(link)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8378ac03/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
index 849f924..ad5f8e5 100644
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ b/ForgeImporters/forgeimporters/google/__init__.py
@@ -1,4 +1,4 @@
-#       Licensed to the Apache Software Foundation (ASF) under one
+#       LNicensed 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

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8378ac03/ForgeImporters/forgeimporters/google/code.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/code.py b/ForgeImporters/forgeimporters/google/code.py
index 11dd7a6..60a0158 100644
--- a/ForgeImporters/forgeimporters/google/code.py
+++ b/ForgeImporters/forgeimporters/google/code.py
@@ -15,6 +15,8 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
+import urllib2
+
 import formencode as fe
 from formencode import validators as fev
 
@@ -22,6 +24,7 @@ from pylons import tmpl_context as c
 from pylons import app_globals as g
 from tg import (
         expose,
+        flash,
         redirect,
         validate,
         )
@@ -31,25 +34,30 @@ from tg.decorators import (
         )
 
 from allura.controllers import BaseController
-from allura.lib.decorators import require_post
+from allura.lib import validators as v
+from allura.lib.decorators import require_post, task
 
 from forgeimporters.base import ToolImporter
 from forgeimporters.google import GoogleCodeProjectExtractor
 
+REPO_APPS = {}
 TARGET_APPS = []
 try:
     from forgehg.hg_main import ForgeHgApp
     TARGET_APPS.append(ForgeHgApp)
+    REPO_APPS['hg'] = ForgeHgApp
 except ImportError:
     pass
 try:
     from forgegit.git_main import ForgeGitApp
     TARGET_APPS.append(ForgeGitApp)
+    REPO_APPS['git'] = ForgeGitApp
 except ImportError:
     pass
 try:
     from forgesvn.svn_main import ForgeSVNApp
     TARGET_APPS.append(ForgeSVNApp)
+    REPO_APPS['svn'] = ForgeSVNApp
 except ImportError:
     pass
 
@@ -69,28 +77,70 @@ def get_repo_url(project_name, type_):
     return REPO_URLS[type_].format(project_name)
 
 
-class GoogleRepoImportSchema(fe.Schema):
+def get_repo_class(type_):
+    return REPO_APPS[type_]
+
+
+@task(notifications_disabled=True)
+def import_tool(**kw):
+    GoogleRepoImporter().import_tool(c.project, c.user, **kw)
+
+
+class GoogleRepoImportForm(fe.schema.Schema):
     gc_project_name = fev.UnicodeString(not_empty=True)
     mount_point = fev.UnicodeString()
     mount_label = fev.UnicodeString()
 
+    def _to_python(self, value, state):
+        value = super(self.__class__, self)._to_python(value, state)
+
+        gc_project_name = value['gc_project_name']
+        mount_point = value['mount_point']
+        try:
+            repo_type = GoogleCodeProjectExtractor(gc_project_name).get_repo_type()
+        except urllib2.HTTPError as e:
+            if e.code == 404:
+                msg = 'No such project'
+            else:
+                msg = str(e)
+            msg = 'gc_project_name:' + msg
+            raise fe.Invalid(msg, value, state)
+        except Exception:
+            raise
+        tool_class = REPO_APPS[repo_type]
+        try:
+            v.MountPointValidator(tool_class).to_python(mount_point)
+        except fe.Invalid as e:
+            raise fe.Invalid('mount_point:' + str(e), value, state)
+        return value
+
 
 class GoogleRepoImportController(BaseController):
+    def __init__(self):
+        self.importer = GoogleRepoImporter()
+
+    @property
+    def target_app(self):
+        return self.importer.target_app[0]
+
     @with_trailing_slash
     @expose('jinja:forgeimporters.google:templates/code/index.html')
     def index(self, **kw):
-        return {}
+        return dict(importer=self.importer,
+                target_app=self.target_app)
 
     @without_trailing_slash
     @expose()
     @require_post()
-    @validate(GoogleRepoImportSchema(), error_handler=index)
+    @validate(GoogleRepoImportForm(), error_handler=index)
     def create(self, gc_project_name, mount_point, mount_label, **kw):
-        app = GoogleRepoImporter().import_tool(c.project, c.user,
+        import_tool.post(
                 project_name=gc_project_name,
                 mount_point=mount_point,
                 mount_label=mount_label)
-        redirect(app.url())
+        flash('Repo import has begun. Your new repo will be available '
+                'when the import is complete.')
+        redirect(c.project.url() + 'admin/')
 
 
 class GoogleRepoImporter(ToolImporter):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8378ac03/ForgeImporters/forgeimporters/google/templates/code/index.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/templates/code/index.html b/ForgeImporters/forgeimporters/google/templates/code/index.html
index 7bace3a..e2cef0c 100644
--- a/ForgeImporters/forgeimporters/google/templates/code/index.html
+++ b/ForgeImporters/forgeimporters/google/templates/code/index.html
@@ -16,27 +16,16 @@
        specific language governing permissions and limitations
        under the License.
 -#}
-{% extends g.theme.master %}
+{% extends 'forgeimporters:templates/importer_base.html' %}
 
 {% block title %}
-{{c.project.name}} / Import Google Code Repo
+{{c.project.name}} / Import your repo from Google Code
 {% endblock %}
 
-{% block header %}
-Import a Repo from a Google Code project
-{% endblock %}
-
-{% block content %}
-<form action="create" method="post" class="pad">
+{% block importer_fields %}
+<div>
   <label for="gc_project_name">Google Code project name (as it appears in a URL)</label>
-  <input name="gc_project_name" />
-
-  <label for="mount_label">Label</label>
-  <input name="mount_label" value="Source" />
-
-  <label for="mount_point">Mount Point</label>
-  <input name="mount_point" value="source" />
-
-  <input type="submit" />
-</form>
+  <input name="gc_project_name" value="{{ c.form_values['gc_project_name'] }}" />
+  {{ error('gc_project_name') }}
+</div>
 {% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8378ac03/ForgeImporters/forgeimporters/google/templates/tracker/index.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/templates/tracker/index.html b/ForgeImporters/forgeimporters/google/templates/tracker/index.html
new file mode 100644
index 0000000..08d0084
--- /dev/null
+++ b/ForgeImporters/forgeimporters/google/templates/tracker/index.html
@@ -0,0 +1,27 @@
+{#-
+       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.
+-#}
+{% extends 'forgeimporters:templates/importer_base.html' %}
+
+{% block importer_fields %}
+<div>
+  <label for="gc_project_name">Google Code project name (as it appears in a URL)</label>
+  <input name="gc_project_name" value="{{ c.form_values['gc_project_name'] }}" />
+  {{ error('gc_project_name') }}
+</div>
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8378ac03/ForgeImporters/forgeimporters/google/tests/test_code.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tests/test_code.py b/ForgeImporters/forgeimporters/google/tests/test_code.py
index 950246a..c6874ad 100644
--- a/ForgeImporters/forgeimporters/google/tests/test_code.py
+++ b/ForgeImporters/forgeimporters/google/tests/test_code.py
@@ -89,12 +89,8 @@ class TestGoogleRepoImportController(TestController, TestCase):
         self.assertIsNotNone(r.html.find(attrs=dict(name="mount_point")))
 
     @with_svn
-    @patch('forgeimporters.google.code.GoogleRepoImporter')
-    def test_create(self, gri):
-        from allura import model as M
-        gri = gri.return_value
-        gri.import_tool.return_value = Mock()
-        gri.import_tool.return_value.url.return_value = '/p/{}/mymount'.format(test_project_with_repo)
+    @patch('forgeimporters.google.code.import_tool')
+    def test_create(self, import_tool):
         params = dict(gc_project_name='poop',
                 mount_label='mylabel',
                 mount_point='mymount',
@@ -102,8 +98,7 @@ class TestGoogleRepoImportController(TestController, TestCase):
         r = self.app.post('/p/{}/admin/src/_importer/create'.format(test_project_with_repo),
                 params,
                 status=302)
-        project = M.Project.query.get(shortname=test_project_with_repo)
-        self.assertEqual(r.location, 'http://localhost/p/{}/mymount'.format(test_project_with_repo))
-        self.assertEqual(project._id, gri.import_tool.call_args[0][0]._id)
-        self.assertEqual(u'mymount', gri.import_tool.call_args[1]['mount_point'])
-        self.assertEqual(u'mylabel', gri.import_tool.call_args[1]['mount_label'])
+        self.assertEqual(r.location, 'http://localhost/p/{}/admin/'.format(test_project_with_repo))
+        self.assertEqual(u'mymount', import_tool.post.call_args[1]['mount_point'])
+        self.assertEqual(u'mylabel', import_tool.post.call_args[1]['mount_label'])
+        self.assertEqual(u'poop', import_tool.post.call_args[1]['project_name'])

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8378ac03/ForgeImporters/forgeimporters/google/tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tracker.py b/ForgeImporters/forgeimporters/google/tracker.py
index 8b1747f..b7fccbe 100644
--- a/ForgeImporters/forgeimporters/google/tracker.py
+++ b/ForgeImporters/forgeimporters/google/tracker.py
@@ -18,23 +18,81 @@
 from collections import defaultdict
 from datetime import datetime
 
+from formencode import validators as fev
+
 from pylons import tmpl_context as c
 from pylons import app_globals as g
 from ming.orm import session, ThreadLocalORMSession
 
 from allura import model as M
+#import gdata
+gdata = None
+from tg import (
+        expose,
+        flash,
+        redirect,
+        validate,
+        )
+from tg.decorators import (
+        with_trailing_slash,
+        without_trailing_slash,
+        )
+
+from allura.controllers import BaseController
 from allura.lib import helpers as h
+from allura.lib.decorators import require_post, task
 
 from forgetracker.tracker_main import ForgeTrackerApp
 from forgetracker import model as TM
-from ..base import ToolImporter
 from . import GoogleCodeProjectExtractor
+from forgeimporters.base import (
+        ToolImporter,
+        ToolImportForm,
+        )
+
+
+@task(notifications_disabled=True)
+def import_tool(**kw):
+    GoogleCodeTrackerImporter().import_tool(c.project, c.user, **kw)
+
+
+class GoogleCodeTrackerImportForm(ToolImportForm):
+    gc_project_name = fev.UnicodeString(not_empty=True)
+
+
+class GoogleCodeTrackerImportController(BaseController):
+    def __init__(self):
+        self.importer = GoogleCodeTrackerImporter()
+
+    @property
+    def target_app(self):
+        return self.importer.target_app
+
+    @with_trailing_slash
+    @expose('jinja:forgeimporters.google:templates/tracker/index.html')
+    def index(self, **kw):
+        return dict(importer=self.importer,
+                target_app=self.target_app)
+
+    @without_trailing_slash
+    @expose()
+    @require_post()
+    @validate(GoogleCodeTrackerImportForm(ForgeTrackerApp), error_handler=index)
+    def create(self, gc_project_name, mount_point, mount_label, **kw):
+        import_tool.post(
+                project_name=gc_project_name,
+                mount_point=mount_point,
+                mount_label=mount_label,
+                )
+        flash('Ticket import has begun. Your new tracker will be available '
+                'when the import is complete.')
+        redirect(c.project.url() + 'admin/')
 
 
 class GoogleCodeTrackerImporter(ToolImporter):
     source = 'Google Code'
     target_app = ForgeTrackerApp
-    controller = None
+    controller = GoogleCodeTrackerImportController
     tool_label = 'Issues'
 
     field_types = defaultdict(lambda: 'string',

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8378ac03/ForgeImporters/forgeimporters/templates/importer_base.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/templates/importer_base.html b/ForgeImporters/forgeimporters/templates/importer_base.html
new file mode 100644
index 0000000..4bdfe0f
--- /dev/null
+++ b/ForgeImporters/forgeimporters/templates/importer_base.html
@@ -0,0 +1,80 @@
+{#-
+       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.
+-#}
+{% extends g.theme.master %}
+
+{% block title %}
+{{c.project.name}} / {{ importer.tool_description }}
+{% endblock %}
+
+{% block header %}
+{{ importer.tool_description }}
+{% endblock %}
+
+{% block extra_css %}
+  <style type="text/css">
+    form {
+      padding: 0 20px 20px 20px;
+    }
+    form label {
+      display: inline-block;
+      width: 30%;
+      vertical-align: top;
+    }
+    form > div {
+      margin-bottom: 10px;
+    }
+    form > div input {
+      width: 30%;
+      vertical-align: top;
+    }
+    form .error {
+      display: inline-block;
+      color: #f00;
+      background: none;
+      border: none;
+      margin: 0;
+      width: 30%;
+    }
+  </style>
+{% endblock %}
+
+{%- macro error(field_name) %}
+  {% if c.form_errors[field_name] %}
+  <div class="error">{{c.form_errors[field_name]}}</div>
+  {% endif %}
+{%- endmacro %}
+
+{% block content %}
+<form action="create" method="post" enctype="multipart/form-data">
+  {% block importer_fields %}
+  {% endblock %}
+  <div>
+    <label for="mount_label">Label</label>
+    <input name="mount_label" value="{{ c.form_values['mount_label'] or target_app.default_mount_label }}" />
+      {{ error('mount_label') }}
+  </div>
+  <div>
+    <label for="mount_point">Mount Point</label>
+    <input name="mount_point" value="{{ c.form_values['mount_point'] or target_app.default_mount_point }}" />
+      {{ error('mount_point') }}
+  </div>
+
+  <input type="submit" />
+</form>
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8378ac03/ForgeImporters/forgeimporters/tests/google/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_tracker.py b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
index 4a7c28f..3c7f0aa 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
@@ -16,9 +16,12 @@
 #       under the License.
 
 from datetime import datetime
-from operator import itemgetter
 from unittest import TestCase
 import mock
+from mock import patch
+
+from allura.tests import TestController
+from allura.tests.decorators import with_tracker
 
 from ...google import tracker
 
@@ -239,3 +242,32 @@ class TestTrackerImporter(TestCase):
                     'options': 'foo bar',
                 },
             ])
+
+
+class TestGoogleCodeTrackerImportController(TestController, TestCase):
+    def setUp(self):
+        """Mount Google Code importer on the Tracker admin controller"""
+        super(TestGoogleCodeTrackerImportController, self).setUp()
+        from forgetracker.tracker_main import TrackerAdminController
+        TrackerAdminController._importer = tracker.GoogleCodeTrackerImportController()
+
+    @with_tracker
+    def test_index(self):
+        r = self.app.get('/p/test/admin/bugs/_importer/')
+        self.assertIsNotNone(r.html.find(attrs=dict(name="gc_project_name")))
+        self.assertIsNotNone(r.html.find(attrs=dict(name="mount_label")))
+        self.assertIsNotNone(r.html.find(attrs=dict(name="mount_point")))
+
+    @with_tracker
+    @patch('forgeimporters.google.tracker.import_tool')
+    def test_create(self, import_tool):
+        params = dict(gc_project_name='test',
+                mount_label='mylabel',
+                mount_point='mymount',
+                )
+        r = self.app.post('/p/test/admin/bugs/_importer/create', params,
+                status=302)
+        self.assertEqual(r.location, 'http://localhost/p/test/admin/')
+        self.assertEqual(u'mymount', import_tool.post.call_args[1]['mount_point'])
+        self.assertEqual(u'mylabel', import_tool.post.call_args[1]['mount_label'])
+        self.assertEqual(u'test', import_tool.post.call_args[1]['project_name'])

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8378ac03/ForgeImporters/forgeimporters/trac/templates/tickets/index.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/templates/tickets/index.html b/ForgeImporters/forgeimporters/trac/templates/tickets/index.html
index 7c278b0..42b8a9f 100644
--- a/ForgeImporters/forgeimporters/trac/templates/tickets/index.html
+++ b/ForgeImporters/forgeimporters/trac/templates/tickets/index.html
@@ -16,30 +16,19 @@
        specific language governing permissions and limitations
        under the License.
 -#}
-{% extends g.theme.master %}
-
-{% block title %}
-{{c.project.name}} / Import Trac Tickets
-{% endblock %}
-
-{% block header %}
-Import tickets from Trac
-{% endblock %}
-
-{% block content %}
-<form action="create" method="post" enctype="multipart/form-data" class="pad">
-  <label for="trac_url">URL of the Trac instance</label>
-  <input name="trac_url" />
-
-  <label for="user_map">JSON file mapping Trac usernames to Allura usernames (optional)</label>
-  <input name="user_map" type="file" />
-
-  <label for="mount_label">Label</label>
-  <input name="mount_label" value="Source" />
-
-  <label for="mount_point">Mount Point</label>
-  <input name="mount_point" value="source" />
-
-  <input type="submit" />
-</form>
+{% extends 'forgeimporters:templates/importer_base.html' %}
+
+{% block importer_fields %}
+  <div>
+    <label for="trac_url">URL of the Trac instance</label>
+    <input name="trac_url" value="{{ c.form_values['trac_url'] }}" />
+    {{ error('trac_url') }}
+  </div>
+  <div>
+    <label for="user_map">User Map (optional)
+      <br><small>JSON file mapping Trac usernames to Allura usernames</small>
+    </label>
+    <input name="user_map" type="file" />
+    {{ error('user_map') }}
+  </div>
 {% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8378ac03/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/tests/test_tickets.py b/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
index 2a539df..953c6d7 100644
--- a/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
+++ b/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
@@ -84,12 +84,8 @@ class TestTracTicketImportController(TestController, TestCase):
         self.assertIsNotNone(r.html.find(attrs=dict(name="mount_point")))
 
     @with_tracker
-    @patch('forgeimporters.trac.tickets.TracTicketImporter')
-    def test_create(self, importer):
-        from allura import model as M
-        importer = importer.return_value
-        importer.import_tool.return_value = Mock()
-        importer.import_tool.return_value.url.return_value = '/p/test/mymount'
+    @patch('forgeimporters.trac.tickets.import_tool')
+    def test_create(self, import_tool):
         params = dict(trac_url='http://example.com/trac/url',
                 mount_label='mylabel',
                 mount_point='mymount',
@@ -97,10 +93,8 @@ class TestTracTicketImportController(TestController, TestCase):
         r = self.app.post('/p/test/admin/bugs/_importer/create', params,
                 upload_files=[('user_map', 'myfile', '{"orig_user": "new_user"}')],
                 status=302)
-        project = M.Project.query.get(shortname='test')
-        self.assertEqual(r.location, 'http://localhost/p/test/mymount')
-        self.assertEqual(project._id, importer.import_tool.call_args[0][0]._id)
-        self.assertEqual(u'mymount', importer.import_tool.call_args[1]['mount_point'])
-        self.assertEqual(u'mylabel', importer.import_tool.call_args[1]['mount_label'])
-        self.assertEqual('{"orig_user": "new_user"}', importer.import_tool.call_args[1]['user_map'])
-        self.assertEqual(u'http://example.com/trac/url', importer.import_tool.call_args[1]['trac_url'])
+        self.assertEqual(r.location, 'http://localhost/p/test/admin/')
+        self.assertEqual(u'mymount', import_tool.post.call_args[1]['mount_point'])
+        self.assertEqual(u'mylabel', import_tool.post.call_args[1]['mount_label'])
+        self.assertEqual('{"orig_user": "new_user"}', import_tool.post.call_args[1]['user_map'])
+        self.assertEqual(u'http://example.com/trac/url', import_tool.post.call_args[1]['trac_url'])

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8378ac03/ForgeImporters/forgeimporters/trac/tickets.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/tickets.py b/ForgeImporters/forgeimporters/trac/tickets.py
index dfbb2a2..3e0e486 100644
--- a/ForgeImporters/forgeimporters/trac/tickets.py
+++ b/ForgeImporters/forgeimporters/trac/tickets.py
@@ -21,7 +21,6 @@ from datetime import (
         )
 import json
 
-import formencode as fe
 from formencode import validators as fev
 
 from ming.orm import session
@@ -30,6 +29,7 @@ from pylons import app_globals as g
 from tg import (
         config,
         expose,
+        flash,
         redirect,
         validate,
         )
@@ -39,44 +39,60 @@ from tg.decorators import (
         )
 
 from allura.controllers import BaseController
-from allura.lib.decorators import require_post
+from allura.lib.decorators import require_post, task
 from allura.lib.import_api import AlluraImportApiClient
-from allura.lib.validators import UserMapJsonFile
+from allura.lib import validators as v
 from allura.model import ApiTicket
 from allura.scripts.trac_export import (
         TracExport,
         DateJSONEncoder,
         )
 
-from forgeimporters.base import ToolImporter
+from forgeimporters.base import (
+        ToolImporter,
+        ToolImportForm,
+        )
 from forgetracker.tracker_main import ForgeTrackerApp
 from forgetracker.scripts.import_tracker import import_tracker
 
 
-class TracTicketImportSchema(fe.Schema):
+@task(notifications_disabled=True)
+def import_tool(**kw):
+    TracTicketImporter().import_tool(c.project, c.user, **kw)
+
+
+class TracTicketImportForm(ToolImportForm):
     trac_url = fev.URL(not_empty=True)
-    user_map = UserMapJsonFile(as_string=True)
-    mount_point = fev.UnicodeString()
-    mount_label = fev.UnicodeString()
+    user_map = v.UserMapJsonFile(as_string=True)
 
 
 class TracTicketImportController(BaseController):
+    def __init__(self):
+        self.importer = TracTicketImporter()
+
+    @property
+    def target_app(self):
+        return self.importer.target_app
+
     @with_trailing_slash
     @expose('jinja:forgeimporters.trac:templates/tickets/index.html')
     def index(self, **kw):
-        return {}
+        return dict(importer=self.importer,
+                target_app=self.target_app)
 
     @without_trailing_slash
     @expose()
     @require_post()
-    @validate(TracTicketImportSchema(), error_handler=index)
+    @validate(TracTicketImportForm(ForgeTrackerApp), error_handler=index)
     def create(self, trac_url, mount_point, mount_label, user_map=None, **kw):
-        app = TracTicketImporter().import_tool(c.project, c.user,
+        import_tool.post(
                 mount_point=mount_point,
                 mount_label=mount_label,
                 trac_url=trac_url,
                 user_map=user_map)
-        redirect(app.url())
+        flash('Ticket import has begun. Your new tracker will be available '
+                'when the import is complete.')
+        redirect(c.project.url() + 'admin/')
 
 
 class TracTicketImporter(ToolImporter):


[09/13] git commit: [#6526] Handle c not having 'project' attr

Posted by tv...@apache.org.
[#6526] Handle c not having 'project' attr

Signed-off-by: Tim Van Steenburgh <tv...@gmail.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/9704ca5c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/9704ca5c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/9704ca5c

Branch: refs/heads/master
Commit: 9704ca5cfc8e6e17622e60094bf48322effc55ea
Parents: 9065167
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Wed Aug 28 15:48:14 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Wed Aug 28 15:48:14 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/validators.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/9704ca5c/Allura/allura/lib/validators.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/validators.py b/Allura/allura/lib/validators.py
index 3295bb0..9d15429 100644
--- a/Allura/allura/lib/validators.py
+++ b/Allura/allura/lib/validators.py
@@ -90,7 +90,8 @@ class MountPointValidator(fev.UnicodeString):
         if mount_point in self.reserved_mount_points:
             raise fe.Invalid('Mount point "%s" is reserved' % mount_point,
                     value, state)
-        if c.project and c.project.app_instance(mount_point) is not None:
+        if (getattr(c, 'project', None) and
+                c.project.app_instance(mount_point) is not None):
             raise fe.Invalid('Mount point "%s" is already in use' % mount_point,
                     value, state)
         return mount_point
@@ -99,7 +100,8 @@ class MountPointValidator(fev.UnicodeString):
         base_mount_point = mount_point = self.app_class.default_mount_point
         i = 0
         while True:
-            if not c.project or c.project.app_instance(mount_point) is None:
+            if (not getattr(c, 'project', None) or
+                    c.project.app_instance(mount_point) is None):
                 return mount_point
             mount_point = base_mount_point + '-%d' % i
             i += 1


[03/13] git commit: [#6482] import page for existing projects

Posted by tv...@apache.org.
[#6482] import page for existing projects


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/f705a179
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/f705a179
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/f705a179

Branch: refs/heads/master
Commit: f705a17907a7ad196b9d19c3086b79bc94221908
Parents: 09f0290
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Fri Aug 9 22:14:07 2013 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Tue Aug 27 17:24:58 2013 +0000

----------------------------------------------------------------------
 ForgeImporters/forgeimporters/base.py           | 45 ++++++++++++--
 .../forgeimporters/templates/list_all.html      | 62 ++++++++++++++++++++
 ForgeImporters/setup.py                         |  3 +
 3 files changed, 104 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f705a179/ForgeImporters/forgeimporters/base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index 19a3d70..620097e 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -24,15 +24,17 @@ from pkg_resources import iter_entry_points
 from BeautifulSoup import BeautifulSoup
 from tg import expose, validate, flash, redirect, config
 from tg.decorators import with_trailing_slash
-from pylons import tmpl_context as c
+from pylons import tmpl_context as c, app_globals as g
 from formencode import validators as fev, schema
+from webob import exc
 
 from allura.lib.decorators import require_post
 from allura.lib.decorators import task
 from allura.lib.security import require_access
-from allura.lib.plugin import ProjectRegistrationProvider
+from allura.lib.plugin import ProjectRegistrationProvider, AdminExtension
 from allura.lib import helpers as h
 from allura.lib import exceptions
+from allura.app import SitemapEntry
 
 from paste.deploy.converters import aslist
 
@@ -273,16 +275,16 @@ class ToolImporter(object):
     source = None  # string description of source, must match project importer
     controller = None
 
-    @classmethod
-    def by_name(self, name):
+    @staticmethod
+    def by_name(name):
         """
         Return a ToolImporter subclass instance given its entry-point name.
         """
         for ep in iter_entry_points('allura.importers', name):
             return ep.load()()
 
-    @classmethod
-    def by_app(self, app):
+    @staticmethod
+    def by_app(app):
         """
         Return a ToolImporter subclass instance given its target_app class.
         """
@@ -350,3 +352,34 @@ class ToolsValidator(fev.Set):
             pl = 's' if len(invalid) > 1 else ''
             raise fev.Invalid('Invalid tool%s selected: %s' % (pl, ', '.join(invalid)), value, state)
         return valid
+
+class ProjectToolsImportController(object):
+    '''List all importers available'''
+
+    @with_trailing_slash
+    @expose('jinja:forgeimporters:templates/list_all.html')
+    def index(self, *a, **kw):
+        importers = {}
+        for app_name, app in g.entry_points['tool'].iteritems():
+            importers[app] = ToolImporter.by_app(app)
+        return {
+            'importers': importers
+        }
+
+    @expose()
+    def _lookup(self, name, *remainder):
+        import_tool = ToolImporter.by_name(name)
+        if import_tool:
+            return import_tool.controller(), remainder
+        else:
+            raise exc.HTTPNotFound
+
+class ImportAdminExtension(AdminExtension):
+    '''Add import link to project admin sidebar'''
+
+    project_admin_controllers = {'import': ProjectToolsImportController}
+
+    def update_project_sidebar_menu(self, sidebar_links):
+        base_url = c.project.url() + 'admin/ext/'
+        link = SitemapEntry('Import', base_url+'import')
+        sidebar_links.append(link)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f705a179/ForgeImporters/forgeimporters/templates/list_all.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/templates/list_all.html b/ForgeImporters/forgeimporters/templates/list_all.html
new file mode 100644
index 0000000..58c9f34
--- /dev/null
+++ b/ForgeImporters/forgeimporters/templates/list_all.html
@@ -0,0 +1,62 @@
+{#-
+       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.
+-#}
+{% extends g.theme.master %}
+{% import 'allura:templates/jinja_master/lib.html' as lib with context %}
+
+{% block title %}{{c.project.name}} / Import{% endblock %}
+
+{% block header %}Import from external sources{% endblock %}
+
+{% block extra_css %}
+<style type="text/css">
+    .tool {
+        margin-bottom: 3em;
+    }
+    .tool img {
+        float: left;
+        margin: 0 1em;
+    }
+    .importer .descr {
+        margin: 0 2em 1em 2em;
+    }
+</style>
+{% endblock %}
+
+{% block content %}
+    {% for tool, tool_importers in importers.iteritems() %}
+        <div class="tool">
+        {% for importer_name, importer in tool_importers.iteritems() %}
+            {% if loop.first %}
+                <img src="{{ g.theme.app_icon_url(tool, 48) }}" alt="{{ tool.tool_label }} icon">
+                <h2>{{ tool.tool_label }}</h2>
+            {% endif %}
+            <div class="importer">
+                <a href="{{importer_name}}"><h3>
+                {{importer.source}}:
+                {{importer.tool_label}}
+                </h3>
+                </a>
+                <div class="descr">
+                {{importer.tool_description}}
+                </div>
+            </div>
+        {% endfor %}
+        </div>
+    {% endfor %}
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f705a179/ForgeImporters/setup.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/setup.py b/ForgeImporters/setup.py
index cec76b4..d070782 100644
--- a/ForgeImporters/setup.py
+++ b/ForgeImporters/setup.py
@@ -42,4 +42,7 @@ setup(name='ForgeImporters',
       google-code-tracker = forgeimporters.google.tracker:GoogleCodeTrackerImporter
       google-code-repo = forgeimporters.google.code:GoogleRepoImporter
       trac-tickets = forgeimporters.trac.tickets:TracTicketImporter
+
+      [allura.admin]
+      importers = forgeimporters.base:ImportAdminExtension
       """,)


[13/13] git commit: put middleware back in proper place so error pages work correctly (bug introduced in 9a1363)

Posted by tv...@apache.org.
put middleware back in proper place so error pages work correctly (bug introduced in 9a1363)


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/6769dc23
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/6769dc23
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/6769dc23

Branch: refs/heads/master
Commit: 6769dc236d4002e9da51c3cb99439c233fb8a8b2
Parents: 1581f29
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Wed Aug 28 19:02:12 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Wed Aug 28 19:05:47 2013 +0000

----------------------------------------------------------------------
 Allura/allura/config/middleware.py | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6769dc23/Allura/allura/config/middleware.py
----------------------------------------------------------------------
diff --git a/Allura/allura/config/middleware.py b/Allura/allura/config/middleware.py
index 1e9b0c7..7395f93 100644
--- a/Allura/allura/config/middleware.py
+++ b/Allura/allura/config/middleware.py
@@ -161,15 +161,17 @@ def _make_core_app(root, global_conf, full_stack=True, **app_conf):
     #    streaming=true ensures they won't be cleaned up till
     #    the WSGI application's iterator is exhausted
     app = RegistryManager(app, streaming=True)
-    # Make sure that the wsgi.scheme is set appropriately when we
-    # have the funky HTTP_X_SFINC_SSL  environ var
-    if asbool(app_conf.get('auth.method', 'local')=='sfx'):
-        app = set_scheme_middleware(app)
     # "task" wsgi would get a 2nd request to /error/document if we used this middleware
     if config.get('override_root') != 'task':
         # Converts exceptions to HTTP errors, shows traceback in debug mode
         tg.error.footer_html = '<!-- %s %s -->'  # don't use TG footer with extra CSS & images that take time to load
         app = tg.error.ErrorHandler(app, global_conf, **config['pylons.errorware'])
+
+        # Make sure that the wsgi.scheme is set appropriately when we
+        # have the funky HTTP_X_SFINC_SSL  environ var
+        if asbool(app_conf.get('auth.method', 'local')=='sfx'):
+            app = set_scheme_middleware(app)
+        
         # Redirect some status codes to /error/document
         if asbool(config['debug']):
             app = StatusCodeRedirect(app, base_config.handle_status_codes)