You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by he...@apache.org on 2016/01/27 22:39:26 UTC

[24/29] allura git commit: [#8054] delete Google Code importers and tests

[#8054] delete Google Code importers and tests


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

Branch: refs/heads/hs/8046
Commit: b956fe30b11639df2cb68374eae5b221fa72e88c
Parents: c5b6ce5
Author: Dave Brondsema <da...@brondsema.net>
Authored: Tue Jan 26 13:58:43 2016 -0500
Committer: Heith Seewald <he...@gmail.com>
Committed: Wed Jan 27 13:42:50 2016 -0500

----------------------------------------------------------------------
 ForgeImporters/docs/importers/google.rst        |  30 -
 .../forgeimporters/google/__init__.py           | 449 --------------
 ForgeImporters/forgeimporters/google/code.py    | 154 -----
 ForgeImporters/forgeimporters/google/project.py |  68 ---
 ForgeImporters/forgeimporters/google/tasks.py   |  39 --
 .../google/templates/code/index.html            |  31 -
 .../google/templates/project.html               |  68 ---
 .../google/templates/tracker/index.html         |  27 -
 .../forgeimporters/google/tests/__init__.py     |  16 -
 .../forgeimporters/google/tests/test_code.py    | 146 -----
 .../forgeimporters/google/tests/test_init.py    | 130 ----
 ForgeImporters/forgeimporters/google/tracker.py | 224 -------
 .../tests/data/google/empty-issue.html          | 306 ----------
 .../data/google/test-issue-first-page.html      | 548 -----------------
 .../tests/data/google/test-issue-prev-page.html | 431 -------------
 .../tests/data/google/test-issue.html           | 535 ----------------
 .../forgeimporters/tests/google/__init__.py     |  16 -
 .../tests/google/functional/__init__.py         |  16 -
 .../tests/google/functional/test_tracker.py     | 316 ----------
 .../tests/google/test_extractor.py              | 607 -------------------
 .../forgeimporters/tests/google/test_tasks.py   |  33 -
 .../forgeimporters/tests/google/test_tracker.py | 336 ----------
 22 files changed, 4526 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/b956fe30/ForgeImporters/docs/importers/google.rst
----------------------------------------------------------------------
diff --git a/ForgeImporters/docs/importers/google.rst b/ForgeImporters/docs/importers/google.rst
deleted file mode 100644
index 5ed7306..0000000
--- a/ForgeImporters/docs/importers/google.rst
+++ /dev/null
@@ -1,30 +0,0 @@
-..     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.
-
-Google Code
-===========
-
-This importer imports projects and tools from Google Code.
-
-:mod:`forgeimporters.google`
-----------------------------
-
-.. autoclass:: forgeimporters.google.project.GoogleCodeProjectImporter
-   :members:
-
-.. autoclass:: forgeimporters.google.tracker.GoogleCodeTrackerImporter
-   :members:

http://git-wip-us.apache.org/repos/asf/allura/blob/b956fe30/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
deleted file mode 100644
index 302544e..0000000
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ /dev/null
@@ -1,449 +0,0 @@
-#       Licensed to the Apache Software Foundation (ASF) under one
-#       or more contributor license agreements.  See the NOTICE file
-#       distributed with this work for additional information
-#       regarding copyright ownership.  The ASF licenses this file
-#       to you under the Apache License, Version 2.0 (the
-#       "License"); you may not use this file except in compliance
-#       with the License.  You may obtain a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#       Unless required by applicable law or agreed to in writing,
-#       software distributed under the License is distributed on an
-#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#       KIND, either express or implied.  See the License for the
-#       specific language governing permissions and limitations
-#       under the License.
-
-import re
-import urllib
-from urllib2 import HTTPError
-from urlparse import urlparse, urljoin, parse_qs
-from collections import defaultdict
-import logging
-import os
-
-import requests
-from BeautifulSoup import BeautifulSoup
-from formencode import validators as fev
-
-from allura.lib import helpers as h
-from allura import model as M
-from forgeimporters.base import ProjectExtractor
-from forgeimporters.base import File
-
-
-log = logging.getLogger(__name__)
-
-
-def _as_text(node, chunks=None):
-    """
-    Similar to node.text, but preserves whitespace around tags,
-    and converts <br/>s to \n.
-    """
-    if chunks is None:
-        chunks = []
-    for n in node:
-        if isinstance(n, basestring):
-            chunks.append(n)
-        elif n.name == 'br':
-            chunks.append('\n')
-        else:
-            _as_text(n, chunks)
-    return ''.join(chunks)
-
-
-def _as_markdown(tag, project_name):
-    fragments = []
-    for fragment in tag:
-        if getattr(fragment, 'name', None) == 'a':
-            href = urlparse(fragment['href'])
-            qs = parse_qs(href.query)
-            gc_link = not href.netloc or href.netloc == 'code.google.com'
-            path_parts = href.path.split('/')
-            target_project = None
-            if gc_link:
-                if len(path_parts) >= 5 and path_parts[1] == 'a':
-                    target_project = '/'.join(path_parts[1:5])
-                elif len(path_parts) >= 3:
-                    target_project = path_parts[2]
-            internal_link = target_project == project_name
-            if gc_link and internal_link and 'id' in qs:
-                # rewrite issue 123 project-internal issue links
-                fragment = '[%s](#%s)' % (fragment.text, qs['id'][0])
-            elif gc_link and internal_link and 'r' in qs:
-                # rewrite r123 project-internal revision links
-                fragment = '[r%s]' % qs['r'][0]
-            elif gc_link:
-                # preserve GC-internal links (probably issue PROJECT:123
-                # inter-project issue links)
-                fragment = '[%s](%s)' % (
-                    h.plain2markdown(
-                        fragment.text, preserve_multiple_spaces=True, has_html_entities=True),
-                    # possibly need to adjust this URL for /a/ hosted domain URLs,
-                    # but it seems fragment['href'] always starts with / so it replaces the given path
-                    urljoin('https://code.google.com/p/%s/issues/' %
-                            project_name, fragment['href']),
-                )
-            else:
-                # convert all other links to Markdown syntax
-                fragment = '[%s](%s)' % (fragment.text, fragment['href'])
-        elif getattr(fragment, 'name', None) == 'i':
-            # preserve styling of "(No comment was entered for this change.)"
-            # messages
-            fragment = '*%s*' % h.plain2markdown(fragment.text,
-                                                 preserve_multiple_spaces=True, has_html_entities=True)
-        elif getattr(fragment, 'name', None) == 'b':
-            # preserve styling of issue template
-            fragment = '**%s**' % h.plain2markdown(fragment.text,
-                                                   preserve_multiple_spaces=True, has_html_entities=True)
-        elif getattr(fragment, 'name', None) == 'br':
-            # preserve forced line-breaks
-            fragment = '\n'
-        else:
-            # convert all others to plain MD
-            fragment = h.plain2markdown(
-                unicode(fragment), preserve_multiple_spaces=True, has_html_entities=True)
-        fragments.append(fragment)
-    return ''.join(fragments).strip()
-
-
-def csv_parser(page):
-    lines = page.readlines()
-    if not lines:
-        return []
-    # skip CSV header
-    lines = lines[1:]
-    # skip "next page here" info footer
-    if not lines[-1].startswith('"'):
-        lines.pop()
-    # remove CSV wrapping (quotes, commas, newlines)
-    return [line.strip('",\n') for line in lines]
-
-
-class GoogleCodeProjectNameValidator(fev.FancyValidator):
-    not_empty = True
-    messages = {
-        'invalid': 'Please enter a project URL, or a project name containing '
-                   'only letters, numbers, and dashes.',
-        'unavailable': 'This project is unavailable for import',
-    }
-
-    def _to_python(self, value, state=None):
-        project_name_re = re.compile(r'^[a-z0-9][a-z0-9-]{,61}$')
-        if project_name_re.match(value):
-            # just a name
-            project_name = value
-        else:
-            # try as a URL
-            project_name = None
-            project_name_simple = None
-            url = urlparse(value.strip())
-            if url.netloc.endswith('.googlecode.com'):
-                project_name = url.netloc.split('.')[0]
-            elif url.netloc == 'code.google.com':
-                path_parts = url.path.lstrip('/').split('/')
-                if len(path_parts) >= 2 and path_parts[0] == 'p':
-                    project_name = path_parts[1]
-                elif len(path_parts) >= 4 and path_parts[0] == 'a' and path_parts[2] == 'p':
-                    project_name_simple = path_parts[3]
-                    project_name = '/'.join(path_parts[0:4])
-
-            if not project_name_simple:
-                project_name_simple = project_name
-
-            if not project_name or not project_name_re.match(project_name_simple):
-                raise fev.Invalid(self.message('invalid', state), value, state)
-
-        if not GoogleCodeProjectExtractor(project_name).check_readable():
-            raise fev.Invalid(self.message('unavailable', state), value, state)
-        return project_name
-
-
-def split_project_name(project_name):
-    '''
-    For hosted projects, the project_name includes the hosted domain.  Split, like:
-
-    :param str project_name: "a/eclipselabs.org/p/restclient-tool"
-    :return: ``("/a/eclipselabs.org", "restclient-tool")``
-    '''
-    if project_name.startswith('a/'):
-        hosted_domain_prefix = '/a/' + project_name.split('/')[1]
-        project_name = project_name.split('/')[3]
-    else:
-        hosted_domain_prefix = ''
-        project_name = project_name
-    return hosted_domain_prefix, project_name
-
-
-class GoogleCodeProjectExtractor(ProjectExtractor):
-    BASE_URL = 'http://code.google.com'
-    RE_REPO_TYPE = re.compile(r'(svn|hg|git)')
-
-    PAGE_MAP = {
-        'project_info': BASE_URL + '{hosted_domain_prefix}/p/{project_name}/',
-        'source_browse': BASE_URL + '{hosted_domain_prefix}/p/{project_name}/source/browse/',
-        'issues_csv': BASE_URL + '{hosted_domain_prefix}/p/{project_name}/issues/csv?can=1&colspec=ID&sort=ID&start={start}',
-        'issue': BASE_URL + '{hosted_domain_prefix}/p/{project_name}/issues/detail?id={issue_id}',
-    }
-
-    LICENSE_MAP = defaultdict(lambda: 'Other/Proprietary License', {
-        'Apache License 2.0': 'Apache License V2.0',
-        'Artistic License/GPL': 'Artistic License',
-        'Eclipse Public License 1.0': 'Eclipse Public License',
-        'GNU GPL v2': 'GNU General Public License version 2.0 (GPLv2)',
-        'GNU GPL v3': 'GNU General Public License version 3.0 (GPLv3)',
-        'GNU Lesser GPL': 'GNU Library or Lesser General Public License version 2.0 (LGPLv2)',
-        'MIT License': 'MIT License',
-        'Mozilla Public License 1.1': 'Mozilla Public License 1.1 (MPL 1.1)',
-        'New BSD License': 'BSD License',
-        'Other Open Source': 'Open Software License',
-    })
-
-    DEFAULT_ICON = 'http://www.gstatic.com/codesite/ph/images/defaultlogo.png'
-
-    def get_page_url(self, page_name, **kw):
-        # override, to handle hosted domains
-        hosted_domain_prefix, project_name = split_project_name(self.project_name)
-        return self.PAGE_MAP[page_name].format(
-            project_name=urllib.quote(project_name),
-            hosted_domain_prefix=hosted_domain_prefix,
-            **kw)
-
-    def check_readable(self):
-        resp = requests.head(self.get_page_url('project_info'))
-        return resp.status_code == 200
-
-    def get_short_description(self, project):
-        page = self.get_page('project_info')
-        project.short_description = page.find(
-            itemprop='description').text.strip()
-
-    def get_icon(self, project):
-        page = self.get_page('project_info')
-        icon_url = urljoin(self.url, page.find(itemprop='image').get('src'))
-        if icon_url == self.DEFAULT_ICON:
-            return
-        icon_name = urllib.unquote(urlparse(icon_url).path).split('/')[-1]
-        icon = File(icon_url, icon_name)
-        filetype = icon.type
-        # work around Google Code giving us bogus file type
-        if filetype.startswith('text/html'):
-            filetype = 'image/png'
-        M.ProjectFile.save_image(
-            icon_name, icon.file, filetype,
-            square=True, thumbnail_size=(48, 48),
-            thumbnail_meta={'project_id': project._id, 'category': 'icon'})
-
-    def get_license(self, project):
-        page = self.get_page('project_info')
-        license = page.find(text='Code license').findNext().find(
-            'a').text.strip()
-        trove = M.TroveCategory.query.get(fullname=self.LICENSE_MAP[license])
-        project.trove_license.append(trove._id)
-
-    def get_repo_type(self):
-        page = self.get_page('source_browse')
-        repo_type = page.find(id="crumb_root")
-        if not repo_type:
-            raise Exception("Couldn't detect repo type: no #crumb_root in "
-                            "{0}".format(self.url))
-        re_match = self.RE_REPO_TYPE.match(repo_type.text.lower())
-        if re_match:
-            return re_match.group(0)
-        else:
-            raise Exception("Unknown repo type: {0}".format(repo_type.text))
-
-    @classmethod
-    def iter_issues(cls, project_name):
-        """
-        Iterate over all issues for a project,
-        using paging to keep the responses reasonable.
-        """
-        extractor = cls(project_name)
-        issue_ids = extractor.get_issue_ids(start=0)
-        while issue_ids:
-            for issue_id in sorted(issue_ids):
-                try:
-                    yield (int(issue_id), cls(project_name, 'issue', issue_id=issue_id))
-                except HTTPError as e:
-                    if e.code == 404:
-                        log.warn('Unable to load GC issue: %s #%s: %s: %s',
-                                 project_name, issue_id, e, e.url)
-                        continue
-                    else:
-                        raise
-            # get any new issues that were created while importing
-            # (jumping back a few in case some were deleted and new ones added)
-            new_ids = extractor.get_issue_ids(start=len(issue_ids) - 10)
-            issue_ids = new_ids - issue_ids
-
-    def get_issue_ids(self, start=0):
-        limit = 100
-
-        issue_ids = set()
-        page = self.get_page('issues_csv', parser=csv_parser, start=start)
-        while page:
-            if len(page) <= 0:
-                return
-            issue_ids.update(page)
-            start += limit
-            page = self.get_page('issues_csv', parser=csv_parser, start=start)
-        return issue_ids
-
-    def get_issue_summary(self):
-        text = self.page.find(id='issueheader').findAll(
-            'td', limit=2)[1].span.text.strip()
-        bs = BeautifulSoup(text, convertEntities=BeautifulSoup.HTML_ENTITIES)
-        return bs.text
-
-    def get_issue_description(self):
-        return _as_markdown(self.page.find(id='hc0').pre, self.project_name)
-
-    def get_issue_created_date(self):
-        return self.page.find(id='hc0').find('span', 'date').get('title')
-
-    def get_issue_mod_date(self):
-        comments = list(self.iter_comments())
-        if comments:
-            last_update = comments[-1]
-            return last_update.created_date
-        else:
-            return self.get_issue_created_date()
-
-    def get_issue_creator(self):
-        a = self.page.find(id='hc0').find(True, 'userlink')
-        return UserLink(a)
-
-    def get_issue_status(self):
-        tag = self.page.find(id='issuemeta').find(
-            'th', text=re.compile('Status:')).findNext().span
-        if tag:
-            return tag.text.strip()
-        else:
-            return ''
-
-    def get_issue_owner(self):
-        tag = self.page.find(id='issuemeta').find(
-            'th', text=re.compile('Owner:')).findNext().find(True, 'userlink')
-        if tag:
-            return UserLink(tag)
-        else:
-            return None
-
-    def get_issue_labels(self):
-        label_nodes = self.page.find(id='issuemeta').findAll('a', 'label')
-        return [_as_text(l) for l in label_nodes]
-
-    def get_issue_attachments(self):
-        return _get_attachments(self.page.find(id='hc0'))
-
-    def get_issue_stars(self):
-        stars_re = re.compile(r'(\d+) (person|people) starred this issue')
-        stars = self.page.find(id='issueheader').find(text=stars_re)
-        if stars:
-            return int(stars_re.search(stars).group(1))
-        return 0
-
-    def iter_comments(self):
-        # first, get all pages if there are multiple pages of comments
-        looking_for_comment_pages = True
-        comment_page_urls = [self.url]
-        while looking_for_comment_pages:
-            first_comment = self.page.find('div', 'vt issuecomment')
-            looking_for_comment_pages = False
-            if first_comment and 'cursor_off' not in first_comment['class']:
-                # this is not a real comment, just forward/back links
-                for link in first_comment.findAll('a'):
-                    if link.text.startswith('Older'):
-                        prev_comments_page = urljoin(self.url, link['href'])
-                        comment_page_urls.insert(0, prev_comments_page)
-                        looking_for_comment_pages = True
-                        self.get_page(prev_comments_page)  # prep for next iteration of loop
-
-        # then go through those to get the actual comments
-        for comment_page_url in comment_page_urls:
-            self.get_page(comment_page_url)
-            # regular comments have cursor_off class
-            for comment in self.page.findAll('div', 'cursor_off vt issuecomment'):
-                yield Comment(comment, self.project_name)
-
-
-
-
-
-class UserLink(object):
-
-    def __init__(self, tag):
-        self.name = tag.text.strip()
-        if tag.get('href'):
-            self.url = urljoin(
-                GoogleCodeProjectExtractor.BASE_URL, tag.get('href'))
-        else:
-            self.url = None
-
-    def __str__(self):
-        if self.url:
-            return '[{name}]({url})'.format(name=self.name, url=self.url)
-        else:
-            return self.name
-
-
-def _get_attachments(tag):
-    attachment_links = tag.find('div', 'attachments')
-    if attachment_links:
-        attachments = []
-        for a in attachment_links.findAll('a', text='Download'):
-            url = a.parent.get('href')
-            try:
-                attachment = Attachment(url)
-            except Exception:
-                log.exception('Could not get attachment: %s', url)
-            else:
-                attachments.append(attachment)
-        return attachments
-    else:
-        return []
-
-
-class Comment(object):
-
-    def __init__(self, tag, project_name):
-        self.author = UserLink(
-            tag.find('span', 'author').find(True, 'userlink'))
-        self.created_date = tag.find('span', 'date').get('title')
-        self.body = _as_markdown(tag.find('pre'), project_name)
-        self._get_updates(tag)
-        self.attachments = _get_attachments(tag)
-
-    def _get_updates(self, tag):
-        _updates = tag.find('div', 'updates')
-        self.updates = {
-            b.text: b.nextSibling.strip()
-            for b in _updates.findAll('b')} if _updates else {}
-
-    @property
-    def annotated_text(self):
-        text = (
-            u'*Originally posted by:* {author}\n'
-            u'\n'
-            u'{body}\n'
-            u'\n'
-            u'{updates}'
-        ).format(
-            author=self.author,
-            body=self.body,
-            updates='\n'.join(
-                '**%s** %s' % (k, v)
-                for k, v in self.updates.items()
-            ),
-        )
-        return text
-
-
-class Attachment(File):
-
-    def __init__(self, url):
-        url = urljoin(GoogleCodeProjectExtractor.BASE_URL, url)
-        filename = parse_qs(urlparse(url).query)['name'][0]
-        super(Attachment, self).__init__(url, filename)

http://git-wip-us.apache.org/repos/asf/allura/blob/b956fe30/ForgeImporters/forgeimporters/google/code.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/code.py b/ForgeImporters/forgeimporters/google/code.py
deleted file mode 100644
index 6a3f43c..0000000
--- a/ForgeImporters/forgeimporters/google/code.py
+++ /dev/null
@@ -1,154 +0,0 @@
-#       Licensed to the Apache Software Foundation (ASF) under one
-#       or more contributor license agreements.  See the NOTICE file
-#       distributed with this work for additional information
-#       regarding copyright ownership.  The ASF licenses this file
-#       to you under the Apache License, Version 2.0 (the
-#       "License"); you may not use this file except in compliance
-#       with the License.  You may obtain a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#       Unless required by applicable law or agreed to in writing,
-#       software distributed under the License is distributed on an
-#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#       KIND, either express or implied.  See the License for the
-#       specific language governing permissions and limitations
-#       under the License.
-
-import urllib2
-
-import formencode as fe
-from formencode import validators as fev
-
-from pylons import tmpl_context as c
-from pylons import app_globals as g
-from tg import (
-    expose,
-    flash,
-    redirect,
-)
-from tg.decorators import (
-    with_trailing_slash,
-    without_trailing_slash,
-)
-
-from allura.lib import validators as v
-from allura.lib.decorators import require_post
-from allura import model as M
-
-from forgeimporters.base import (
-    ToolImporter,
-    ToolImportController,
-)
-from forgeimporters.google import GoogleCodeProjectExtractor
-from forgeimporters.google import GoogleCodeProjectNameValidator
-from forgeimporters.google import split_project_name
-
-REPO_URLS = {
-    'svn': 'http://{project_name}.googlecode.com/svn/',
-    'svn-hosted': 'http://svn.codespot.com{hosted_domain_prefix}/{project_name}/',
-    'git': 'https://code.google.com{hosted_domain_prefix}/p/{project_name}/',
-    'hg': 'https://code.google.com{hosted_domain_prefix}/p/{project_name}/',
-}
-
-
-def get_repo_url(project_name, type_):
-    hosted_domain_prefix, project_name = split_project_name(project_name)
-    if hosted_domain_prefix and type_ == 'svn':
-        type_ = 'svn-hosted'
-    return REPO_URLS[type_].format(project_name=project_name,
-                                   hosted_domain_prefix=hosted_domain_prefix)
-
-
-class GoogleRepoImportForm(fe.schema.Schema):
-    gc_project_name = GoogleCodeProjectNameValidator()
-    mount_point = fev.UnicodeString()
-    mount_label = fev.UnicodeString()
-
-    def __init__(self, *args):
-        pass
-
-    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 = g.entry_points['tool'][repo_type]
-        try:
-            value['mount_point'] = 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(ToolImportController):
-    import_form = GoogleRepoImportForm
-
-    @with_trailing_slash
-    @expose('jinja:forgeimporters.google:templates/code/index.html')
-    def index(self, **kw):
-        return dict(importer=self.importer,
-                    target_app=self.target_app)
-
-    @without_trailing_slash
-    @expose()
-    @require_post()
-    def create(self, gc_project_name, mount_point, mount_label, **kw):
-        if self.importer.enforce_limit(c.project):
-            self.importer.post(
-                project_name=gc_project_name,
-                mount_point=mount_point,
-                mount_label=mount_label)
-            flash('Repo import has begun. Your new repo will be available '
-                  'when the import is complete.')
-        else:
-            flash(
-                'There are too many imports pending at this time.  Please wait and try again.', 'error')
-        redirect(c.project.url() + 'admin/')
-
-
-class GoogleRepoImporter(ToolImporter):
-    target_app_ep_names = ('git', 'hg', 'svn')
-    source = 'Google Code'
-    controller = GoogleRepoImportController
-    tool_label = 'Source Code'
-    tool_description = 'Import your primary SVN, Git, or Hg repo from Google Code'
-
-    def import_tool(self, project, user, project_name=None, mount_point=None,
-                    mount_label=None, **kw):
-        """ Import a Google Code repo into a new SVN, Git, or Hg Allura tool.
-
-        """
-        extractor = GoogleCodeProjectExtractor(project_name, 'source_browse')
-        repo_type = extractor.get_repo_type()
-        repo_url = get_repo_url(project_name, repo_type)
-        app = project.install_app(
-            repo_type,
-            mount_point=mount_point or 'code',
-            mount_label=mount_label or 'Code',
-            init_from_url=repo_url,
-            import_id={
-                'source': self.source,
-                'project_name': project_name,
-            }
-        )
-        M.AuditLog.log(
-            'import tool %s from %s on %s' % (
-                app.config.options.mount_point,
-                project_name, self.source,
-            ), project=project, user=user, url=app.url)
-        g.post_event('project_updated')
-        return app

http://git-wip-us.apache.org/repos/asf/allura/blob/b956fe30/ForgeImporters/forgeimporters/google/project.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/project.py b/ForgeImporters/forgeimporters/google/project.py
deleted file mode 100644
index 9ffade1..0000000
--- a/ForgeImporters/forgeimporters/google/project.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#       Licensed to the Apache Software Foundation (ASF) under one
-#       or more contributor license agreements.  See the NOTICE file
-#       distributed with this work for additional information
-#       regarding copyright ownership.  The ASF licenses this file
-#       to you under the Apache License, Version 2.0 (the
-#       "License"); you may not use this file except in compliance
-#       with the License.  You may obtain a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#       Unless required by applicable law or agreed to in writing,
-#       software distributed under the License is distributed on an
-#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#       KIND, either express or implied.  See the License for the
-#       specific language governing permissions and limitations
-#       under the License.
-
-import logging
-
-from tg import expose, validate
-from tg.decorators import with_trailing_slash
-
-from allura.lib.decorators import require_post
-
-from forgeimporters import base
-from forgeimporters.google import tasks
-from forgeimporters.google import GoogleCodeProjectNameValidator
-
-
-log = logging.getLogger(__name__)
-
-
-class GoogleCodeProjectForm(base.ProjectImportForm):
-    project_name = GoogleCodeProjectNameValidator()
-
-
-class GoogleCodeProjectImporter(base.ProjectImporter):
-
-    """
-    Project importer for Google Code.
-
-    This imports project metadata, including summary, icon, and license,
-    as well as providing the UI for importing individual tools during project
-    import.
-    """
-    source = 'Google Code'
-    process_validator = GoogleCodeProjectForm(source)
-    index_template = 'jinja:forgeimporters.google:templates/project.html'
-
-    def after_project_create(self, project, **kw):
-        project.set_tool_data('google-code', project_name=project.name)
-        tasks.import_project_info.post(project.name)
-
-    @with_trailing_slash
-    @expose(index_template)
-    def index(self, **kw):
-        return super(self.__class__, self).index(**kw)
-
-    @require_post()
-    @expose()
-    @validate(process_validator, error_handler=index)
-    def process(self, **kw):
-        return super(self.__class__, self).process(**kw)
-
-    @expose('json:')
-    @validate(process_validator)
-    def check_names(self, **kw):
-        return super(self.__class__, self).check_names(**kw)

http://git-wip-us.apache.org/repos/asf/allura/blob/b956fe30/ForgeImporters/forgeimporters/google/tasks.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tasks.py b/ForgeImporters/forgeimporters/google/tasks.py
deleted file mode 100644
index b0cb76f..0000000
--- a/ForgeImporters/forgeimporters/google/tasks.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#       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.
-
-from pylons import tmpl_context as c
-from pylons import app_globals as g
-
-from ming.orm import ThreadLocalORMSession
-
-from allura.lib.decorators import task
-
-from forgeimporters.base import ImportErrorHandler
-from forgeimporters.google import GoogleCodeProjectExtractor
-
-
-@task
-def import_project_info(project_name):
-    from forgeimporters.google.project import GoogleCodeProjectImporter
-    importer = GoogleCodeProjectImporter(None)
-    with ImportErrorHandler(importer, project_name, c.project) as handler:
-        extractor = GoogleCodeProjectExtractor(project_name, 'project_info')
-        extractor.get_short_description(c.project)
-        extractor.get_icon(c.project)
-        extractor.get_license(c.project)
-        ThreadLocalORMSession.flush_all()
-        g.post_event('project_updated')

http://git-wip-us.apache.org/repos/asf/allura/blob/b956fe30/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
deleted file mode 100644
index e2cef0c..0000000
--- a/ForgeImporters/forgeimporters/google/templates/code/index.html
+++ /dev/null
@@ -1,31 +0,0 @@
-{#-
-       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 title %}
-{{c.project.name}} / Import your repo from Google Code
-{% endblock %}
-
-{% 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/allura/blob/b956fe30/ForgeImporters/forgeimporters/google/templates/project.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/templates/project.html b/ForgeImporters/forgeimporters/google/templates/project.html
deleted file mode 100644
index a00c0dd..0000000
--- a/ForgeImporters/forgeimporters/google/templates/project.html
+++ /dev/null
@@ -1,68 +0,0 @@
-{#-
-       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/project_base.html' %}
-
-{% block extra_js %}
-    {{super()}}
-    <script type="text/javascript">
-        function suggest_name() {  // overrides base suggest_names
-            var $project_shortname = $('#project_shortname');
-            if (!manual) {
-                var name_or_url = $('#project_name').val().replace(/\s/g, '').toLowerCase();
-                name_or_url = name_or_url.replace(/\/$/, '');  // strip any trailing slash
-                var a = $('<a>', {href: name_or_url})[0];  // leverage DOM to parse URL
-                var project_name;
-                var old_style = a.hostname.match(/^(.*)\.googlecode\.com$/);
-                if (old_style) {
-                    project_name = old_style[1];
-                } else {
-                    var parts = a.pathname.split('/');
-                    project_name = parts.pop();
-                }
-                $project_shortname.val(project_name);
-            }
-            $project_shortname.trigger('change');
-        }
-    </script>
-{% endblock %}
-
-{% block project_fields %}
-    <div class="grid-7">
-        <label>Google Project Name or URL</label>
-    </div>
-    <div class="grid-10">
-        <input id="project_name" name="project_name" value="{{c.form_values['project_name']}}" autofocus/>
-        <div id="project_name_error" class="error{% if not c.form_errors['project_name'] %} hidden{% endif %}">
-            {{c.form_errors['project_name']}}
-        </div>
-    </div>
-
-    <div class="grid-7" style="clear:left">
-        <label>{{config.site_name}} URL Name</label>
-    </div>
-    <div class="grid-10">
-        <input id="project_shortname" name="project_shortname" value="{{c.form_values['project_shortname']}}"/>
-        <div id="project_shortname_error" class="error{% if not c.form_errors['project_shortname'] %} hidden{% endif %}">
-            {{c.form_errors['project_shortname']}}
-        </div>
-        <div id="project-url">
-            http://{{request.environ['HTTP_HOST']}}{{importer.neighborhood.url()}}<span id="url-fragment">{{c.form_values['project_shortname']}}</span>
-        </div>
-    </div>
-{% endblock %}

http://git-wip-us.apache.org/repos/asf/allura/blob/b956fe30/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
deleted file mode 100644
index 08d0084..0000000
--- a/ForgeImporters/forgeimporters/google/templates/tracker/index.html
+++ /dev/null
@@ -1,27 +0,0 @@
-{#-
-       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/allura/blob/b956fe30/ForgeImporters/forgeimporters/google/tests/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tests/__init__.py b/ForgeImporters/forgeimporters/google/tests/__init__.py
deleted file mode 100644
index 144e298..0000000
--- a/ForgeImporters/forgeimporters/google/tests/__init__.py
+++ /dev/null
@@ -1,16 +0,0 @@
-#       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.

http://git-wip-us.apache.org/repos/asf/allura/blob/b956fe30/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
deleted file mode 100644
index 1b6cacc..0000000
--- a/ForgeImporters/forgeimporters/google/tests/test_code.py
+++ /dev/null
@@ -1,146 +0,0 @@
-#       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.
-
-from unittest import TestCase
-from mock import Mock, patch
-from ming.odm import ThreadLocalORMSession
-
-from allura.tests import TestController
-from allura import model as M
-
-
-# important to be distinct from 'test' which ForgeSVN uses, so that the
-# tests can run in parallel and not clobber each other
-test_project_with_repo = 'test2'
-
-
-from forgeimporters.google.code import (
-    get_repo_url,
-    GoogleRepoImporter,
-)
-
-
-class TestGetRepoUrl(TestCase):
-
-    def test_svn(self):
-        r = get_repo_url('projname', 'svn')
-        self.assertEqual(r, 'http://projname.googlecode.com/svn/')
-
-    def test_git(self):
-        r = get_repo_url('projname', 'git')
-        self.assertEqual(r, 'https://code.google.com/p/projname/')
-
-    def test_hg(self):
-        r = get_repo_url('projname', 'hg')
-        self.assertEqual(r, 'https://code.google.com/p/projname/')
-
-    def test_svn_hosted(self):
-        r = get_repo_url('a/eclipselabs.org/p/projname', 'svn')
-        self.assertEqual(r, 'http://svn.codespot.com/a/eclipselabs.org/projname/')
-
-    def test_git_hosted(self):
-        r = get_repo_url('a/eclipselabs.org/p/projname', 'git')
-        self.assertEqual(r, 'https://code.google.com/a/eclipselabs.org/p/projname/')
-
-    def test_hg_hosted(self):
-        r = get_repo_url('a/eclipselabs.org/p/projname', 'hg')
-        self.assertEqual(r, 'https://code.google.com/a/eclipselabs.org/p/projname/')
-
-
-class TestGoogleRepoImporter(TestCase):
-
-    def _make_project(self, gc_proj_name=None):
-        project = Mock()
-        project.get_tool_data.side_effect = lambda *args: gc_proj_name
-        return project
-
-    @patch('forgeimporters.google.code.g')
-    @patch('forgeimporters.google.code.M')
-    @patch('forgeimporters.google.code.GoogleCodeProjectExtractor')
-    @patch('forgeimporters.google.code.get_repo_url')
-    def test_import_tool_happy_path(self, get_repo_url, gcpe, M, g):
-        gcpe.return_value.get_repo_type.return_value = 'git'
-        get_repo_url.return_value = 'http://remote/clone/url/'
-        p = self._make_project(gc_proj_name='myproject')
-        u = Mock(name='c.user')
-        app = p.install_app.return_value
-        app.config.options.mount_point = 'code'
-        app.url = 'foo'
-        GoogleRepoImporter().import_tool(p, u, project_name='project_name')
-        get_repo_url.assert_called_once_with('project_name', 'git')
-        p.install_app.assert_called_once_with('git',
-                                              mount_point='code',
-                                              mount_label='Code',
-                                              init_from_url='http://remote/clone/url/',
-                                              import_id={
-                                                  'source': 'Google Code',
-                                                  'project_name': 'project_name',
-                                              },
-                                              )
-        M.AuditLog.log.assert_called_once_with(
-            'import tool code from project_name on Google Code',
-            project=p, user=u, url='foo')
-        g.post_event.assert_called_once_with('project_updated')
-
-
-class TestGoogleRepoImportController(TestController, TestCase):
-
-    def test_index(self):
-        r = self.app.get(
-            '/p/{}/admin/ext/import/google-code-repo/'.format(test_project_with_repo))
-        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")))
-
-    @patch('forgeimporters.google.code.GoogleCodeProjectExtractor')
-    @patch('forgeimporters.base.import_tool')
-    def test_create(self, import_tool, extractor):
-        extractor.return_value.get_repo_type.return_value = 'git'
-        params = dict(gc_project_name='poop',
-                      mount_label='mylabel',
-                      mount_point='mymount',
-                      )
-        r = self.app.post(
-            '/p/{}/admin/ext/import/google-code-repo/create'.format(test_project_with_repo),
-            params,
-            status=302)
-        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'])
-
-    @patch('forgeimporters.google.code.GoogleCodeProjectExtractor')
-    @patch('forgeimporters.base.import_tool')
-    def test_create_limit(self, import_tool, extractor):
-        extractor.return_value.get_repo_type.return_value = 'git'
-        project = M.Project.query.get(shortname=test_project_with_repo)
-        project.set_tool_data('GoogleRepoImporter', pending=1)
-        ThreadLocalORMSession.flush_all()
-        params = dict(gc_project_name='poop',
-                      mount_label='mylabel',
-                      mount_point='mymount',
-                      )
-        r = self.app.post(
-            '/p/{}/admin/ext/import/google-code-repo/create'.format(test_project_with_repo),
-            params,
-            status=302).follow()
-        self.assertIn('Please wait and try again', r)
-        self.assertEqual(import_tool.post.call_count, 0)

http://git-wip-us.apache.org/repos/asf/allura/blob/b956fe30/ForgeImporters/forgeimporters/google/tests/test_init.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tests/test_init.py b/ForgeImporters/forgeimporters/google/tests/test_init.py
deleted file mode 100644
index 37bf4c2..0000000
--- a/ForgeImporters/forgeimporters/google/tests/test_init.py
+++ /dev/null
@@ -1,130 +0,0 @@
-#       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.
-
-from nose.tools import assert_equal
-from mock import patch
-from formencode.validators import Invalid
-from BeautifulSoup import BeautifulSoup
-from IPython.testing.decorators import skipif, module_not_available
-
-from allura.tests import decorators as td
-from forgeimporters.google import GoogleCodeProjectNameValidator, GoogleCodeProjectExtractor
-from forgeimporters.google import _as_markdown
-
-
-class TestGoogleCodeProjectNameValidator(object):
-
-    def setUp(self):
-        self.readable_patcher = patch.object(GoogleCodeProjectExtractor, 'check_readable')
-        self.readable_mock = self.readable_patcher.start()
-        self.readable_mock.return_value = True
-
-    def tearDown(self):
-        self.readable_patcher.stop()
-
-    def test_simple(self):
-        assert_equal(
-            GoogleCodeProjectNameValidator()._to_python('gmapcatcher'),
-            'gmapcatcher'
-        )
-
-    def test_code_dot_google(self):
-        assert_equal(
-            GoogleCodeProjectNameValidator()._to_python('http://code.google.com/p/gmapcatcher/'),
-            'gmapcatcher'
-        )
-        assert_equal(
-            GoogleCodeProjectNameValidator()._to_python('https://code.google.com/p/gmapcatcher/'),
-            'gmapcatcher'
-        )
-
-    def test_googlecode_com(self):
-        assert_equal(
-            GoogleCodeProjectNameValidator()._to_python('http://gmapcatcher.googlecode.com/'),
-            'gmapcatcher'
-        )
-        assert_equal(
-            GoogleCodeProjectNameValidator()._to_python('https://gmapcatcher.googlecode.com/'),
-            'gmapcatcher'
-        )
-
-    def test_not_readable(self):
-        self.readable_mock.return_value = False
-        with td.raises(Invalid):
-            GoogleCodeProjectNameValidator()._to_python('gmapcatcher')
-
-    def test_invalid(self):
-        with td.raises(Invalid):
-            GoogleCodeProjectNameValidator()._to_python('http://code.google.com/')
-        with td.raises(Invalid):
-            GoogleCodeProjectNameValidator()._to_python('http://foobar.com/p/gmapcatcher')
-        with td.raises(Invalid):
-            GoogleCodeProjectNameValidator()._to_python('http://code.google.com/p/asdf_asdf')
-        with td.raises(Invalid):
-            GoogleCodeProjectNameValidator()._to_python('http://code.google.com/x/y/z')
-
-    def test_hosted_domain(self):
-        assert_equal(
-            GoogleCodeProjectNameValidator()._to_python('https://code.google.com/a/eclipselabs.org/p/restclient-tool'),
-            'a/eclipselabs.org/p/restclient-tool'
-        )
-        with td.raises(Invalid):
-            GoogleCodeProjectNameValidator()._to_python('http://code.google.com/a/eclipselabs.org/bogus')
-
-
-class Test_as_markdown(object):
-
-    # this is covered by functional tests (useing test-issue.html)
-    # but adding some unit tests for easier verification of hosted domain link rewriting
-
-    def test_link_within_proj(self):
-        html = BeautifulSoup('''<pre>Foo: <a href="/p/myproj/issues/detail?id=1">issue 1</a></pre>''')
-        assert_equal(
-            _as_markdown(html.first(), 'myproj'),
-            'Foo: [issue 1](#1)'
-        )
-
-    @skipif(module_not_available('html2text'))
-    def test_link_other_proj_has_html2text(self):
-        html = BeautifulSoup('''<pre>Foo: <a href="/p/other-project/issues/detail?id=1">issue other-project:1</a></pre>''')
-        assert_equal(
-            _as_markdown(html.first(), 'myproj'),
-            'Foo: [issue other-project:1](https://code.google.com/p/other-project/issues/detail?id=1)'
-        )
-
-    @td.without_module('html2text')
-    def test_link_other_proj_no_html2text(self):
-        # without html2text, the dash in other-project doesn't get escaped right
-        html = BeautifulSoup('''<pre>Foo: <a href="/p/other-project/issues/detail?id=1">issue other-project:1</a></pre>''')
-        assert_equal(
-            _as_markdown(html.first(), 'myproj'),
-            'Foo: [issue other\\-project:1](https://code.google.com/p/other-project/issues/detail?id=1)'
-        )
-
-    def test_link_hosted_domain_within_proj(self):
-        html = BeautifulSoup('''<pre>Foo: <a href="/a/eclipselabs.org/p/myproj/issues/detail?id=1">issue 1</a></pre>''')
-        assert_equal(
-            _as_markdown(html.first(), 'a/eclipselabs.org/p/myproj'),
-            'Foo: [issue 1](#1)'
-        )
-
-    def test_link_hosted_domain_other_proj(self):
-        html = BeautifulSoup('''<pre>Foo: <a href="/a/eclipselabs.org/p/other-proj/issues/detail?id=1">issue 1</a></pre>''')
-        assert_equal(
-            _as_markdown(html.first(), 'a/eclipselabs.org/p/myproj'),
-            'Foo: [issue 1](https://code.google.com/a/eclipselabs.org/p/other-proj/issues/detail?id=1)'
-        )

http://git-wip-us.apache.org/repos/asf/allura/blob/b956fe30/ForgeImporters/forgeimporters/google/tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tracker.py b/ForgeImporters/forgeimporters/google/tracker.py
deleted file mode 100644
index 7873aa6..0000000
--- a/ForgeImporters/forgeimporters/google/tracker.py
+++ /dev/null
@@ -1,224 +0,0 @@
-#       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.
-
-from collections import defaultdict
-
-from pylons import tmpl_context as c
-from pylons import app_globals as g
-from ming.orm import session, ThreadLocalORMSession
-import dateutil.parser
-
-from tg import (
-    expose,
-    flash,
-    redirect,
-)
-from tg.decorators import (
-    with_trailing_slash,
-    without_trailing_slash,
-)
-
-from allura.lib import helpers as h
-from allura.lib.plugin import ImportIdConverter
-from allura.lib.decorators import require_post
-from allura import model as M
-
-from forgetracker import model as TM
-from forgeimporters.google import GoogleCodeProjectExtractor
-from forgeimporters.google import GoogleCodeProjectNameValidator
-from forgeimporters.base import (
-    ToolImporter,
-    ToolImportForm,
-    ToolImportController,
-)
-
-
-class GoogleCodeTrackerImportForm(ToolImportForm):
-    gc_project_name = GoogleCodeProjectNameValidator()
-
-
-class GoogleCodeTrackerImportController(ToolImportController):
-    import_form = GoogleCodeTrackerImportForm
-
-    @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()
-    def create(self, gc_project_name, mount_point, mount_label, **kw):
-        if self.importer.enforce_limit(c.project):
-            self.importer.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.')
-        else:
-            flash(
-                'There are too many imports pending at this time.  Please wait and try again.', 'error')
-        redirect(c.project.url() + 'admin/')
-
-
-class GoogleCodeTrackerImporter(ToolImporter):
-    source = 'Google Code'
-    target_app_ep_names = 'tickets'
-    controller = GoogleCodeTrackerImportController
-    tool_label = 'Issues'
-    tool_description = 'Import your public tickets from Google Code'
-
-    field_types = defaultdict(lambda: 'string',
-                              milestone='milestone',
-                              priority='select',
-                              type='select',
-                              )
-
-    def __init__(self, *args, **kwargs):
-        super(GoogleCodeTrackerImporter, self).__init__(*args, **kwargs)
-        self.open_milestones = set()
-        self.custom_fields = {}
-        self.max_ticket_num = 0
-
-    def import_tool(self, project, user, project_name, mount_point=None,
-                    mount_label=None, **kw):
-        import_id_converter = ImportIdConverter.get()
-        app = project.install_app('tickets', mount_point, mount_label,
-                                  EnableVoting=True,
-                                  open_status_names='New Accepted Started',
-                                  closed_status_names='Fixed Verified Invalid Duplicate WontFix Done',
-                                  import_id={
-                                      'source': self.source,
-                                      'project_name': project_name,
-                                  },
-                                  )
-        ThreadLocalORMSession.flush_all()
-        try:
-            M.session.artifact_orm_session._get().skip_mod_date = True
-            with h.push_config(c, user=M.User.anonymous(), app=app):
-                for ticket_num, issue in GoogleCodeProjectExtractor.iter_issues(project_name):
-                    self.max_ticket_num = max(ticket_num, self.max_ticket_num)
-                    ticket = TM.Ticket(
-                        app_config_id=app.config._id,
-                        custom_fields=dict(),
-                        ticket_num=ticket_num,
-                        import_id=import_id_converter.expand(ticket_num, app))
-                    self.process_fields(ticket, issue)
-                    self.process_labels(ticket, issue)
-                    self.process_comments(ticket, issue)
-                    session(ticket).flush(ticket)
-                    session(ticket).expunge(ticket)
-                app.globals.custom_fields = self.postprocess_custom_fields()
-                app.globals.last_ticket_num = self.max_ticket_num
-                ThreadLocalORMSession.flush_all()
-            M.AuditLog.log(
-                'import tool %s from %s on %s' % (
-                    app.config.options.mount_point,
-                    project_name, self.source,
-                ),
-                project=project,
-                user=user,
-                url=app.url,
-            )
-            g.post_event('project_updated')
-            app.globals.invalidate_bin_counts()
-            return app
-        except Exception:
-            h.make_app_admin_only(app)
-            raise
-        finally:
-            M.session.artifact_orm_session._get().skip_mod_date = False
-
-    def custom_field(self, name):
-        if name not in self.custom_fields:
-            self.custom_fields[name] = {
-                'type': self.field_types[name.lower()],
-                'label': name,
-                'name': u'_%s' % name.lower(),
-                'options': set(),
-            }
-        return self.custom_fields[name]
-
-    def process_fields(self, ticket, issue):
-        ticket.summary = issue.get_issue_summary()
-        ticket.status = issue.get_issue_status()
-        ticket.created_date = dateutil.parser.parse(
-            issue.get_issue_created_date())
-        ticket.mod_date = dateutil.parser.parse(issue.get_issue_mod_date())
-        ticket.votes_up = issue.get_issue_stars()
-        ticket.votes = issue.get_issue_stars()
-        owner = issue.get_issue_owner()
-        if owner:
-            owner_line = '*Originally owned by:* {owner}\n'.format(owner=owner)
-        else:
-            owner_line = ''
-        ticket.description = (
-            u'*Originally created by:* {creator}\n'
-            u'{owner}'
-            u'\n'
-            u'{body}').format(
-            creator=issue.get_issue_creator(),
-            owner=owner_line,
-            body=issue.get_issue_description(),
-        )
-        ticket.add_multiple_attachments(issue.get_issue_attachments())
-
-    def process_labels(self, ticket, issue):
-        labels = set()
-        custom_fields = defaultdict(set)
-        for label in issue.get_issue_labels():
-            if u'-' in label:
-                name, value = label.split(u'-', 1)
-                cf = self.custom_field(name)
-                cf['options'].add(value)
-                custom_fields[cf['name']].add(value)
-                if cf['name'] == '_milestone' and ticket.status in c.app.globals.open_status_names:
-                    self.open_milestones.add(value)
-            else:
-                labels.add(label)
-        ticket.labels = list(labels)
-        ticket.custom_fields = {n: u', '.join(sorted(v))
-                                for n, v in custom_fields.iteritems()}
-
-    def process_comments(self, ticket, issue):
-        for comment in issue.iter_comments():
-            p = ticket.discussion_thread.add_post(
-                text=comment.annotated_text,
-                ignore_security=True,
-                timestamp=dateutil.parser.parse(comment.created_date),
-            )
-            p.add_multiple_attachments(comment.attachments)
-
-    def postprocess_custom_fields(self):
-        custom_fields = []
-        for name, field in self.custom_fields.iteritems():
-            if field['name'] == '_milestone':
-                field['milestones'] = [{
-                    'name': milestone,
-                    'due_date': None,
-                    'complete': milestone not in self.open_milestones,
-                } for milestone in sorted(field['options'])]
-                field['options'] = ''
-            elif field['type'] == 'select':
-                field['options'] = ' '.join(field['options'])
-            else:
-                field['options'] = ''
-            custom_fields.append(field)
-        return custom_fields

http://git-wip-us.apache.org/repos/asf/allura/blob/b956fe30/ForgeImporters/forgeimporters/tests/data/google/empty-issue.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/data/google/empty-issue.html b/ForgeImporters/forgeimporters/tests/data/google/empty-issue.html
deleted file mode 100644
index b2eef20..0000000
--- a/ForgeImporters/forgeimporters/tests/data/google/empty-issue.html
+++ /dev/null
@@ -1,306 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
-<meta name="ROBOTS" content="NOARCHIVE" />
-<link rel="icon" type="image/vnd.microsoft.icon" href="http://www.gstatic.com/codesite/ph/images/phosting.ico" />
-<script type="text/javascript">
-
-
-
-
- var codesite_token = null;
-
-
- var CS_env = {"assetHostPath":"http://www.gstatic.com/codesite/ph","projectHomeUrl":"/p/allura-google-importer","relativeBaseUrl":"","domainName":null,"projectName":"allura-google-importer","loggedInUserEmail":null,"profileUrl":null,"token":null,"assetVersionPath":"http://www.gstatic.com/codesite/ph/3783617020303179221"};
- var _gaq = _gaq || [];
- _gaq.push(
- ['siteTracker._setAccount', 'UA-18071-1'],
- ['siteTracker._trackPageview']);
-
- (function() {
- var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
- ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
- (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
- })();
-
- </script>
-<title>Issue 5 -
- allura-google-importer -
-
- Empty Issue -
- Import Google Code projects to an Allura forge - Google Project Hosting
- </title>
-<link type="text/css" rel="stylesheet" href="http://www.gstatic.com/codesite/ph/3783617020303179221/css/core.css" />
-<link type="text/css" rel="stylesheet" href="http://www.gstatic.com/codesite/ph/3783617020303179221/css/ph_detail.css" />
-<!--[if IE]>
- <link type="text/css" rel="stylesheet" href="http://www.gstatic.com/codesite/ph/3783617020303179221/css/d_ie.css" >
-<![endif]-->
-<style type="text/css">
- .menuIcon.off { background: no-repeat url(http://www.gstatic.com/codesite/ph/images/dropdown_sprite.gif) 0 -42px }
- .menuIcon.on { background: no-repeat url(http://www.gstatic.com/codesite/ph/images/dropdown_sprite.gif) 0 -28px }
- .menuIcon.down { background: no-repeat url(http://www.gstatic.com/codesite/ph/images/dropdown_sprite.gif) 0 0; }
-
-
- .attachments { width:33%; border-top:2px solid #999; padding-top: 3px; margin-left: .7em;}
- .attachments table { margin-bottom: 0.75em; }
- .attachments table tr td { padding: 0; margin: 0; font-size: 95%; }
- .preview { border: 2px solid #c3d9ff; padding: 1px; }
- .preview:hover { border: 2px solid blue; }
- .label { white-space: nowrap; }
- .derived { font-style:italic }
- .cursor_on .author {
- background: url(http://www.gstatic.com/codesite/ph/images/show-arrow.gif) no-repeat 2px;
- }
- .hiddenform {
- display: none;
- }
-
-
- </style>
-</head>
-<body class="t3">
-<script type="text/javascript">
- window.___gcfg = {lang: 'en'};
- (function()
- {var po = document.createElement("script");
- po.type = "text/javascript"; po.async = true;po.src = "https://apis.google.com/js/plusone.js";
- var s = document.getElementsByTagName("script")[0];
- s.parentNode.insertBefore(po, s);
- })();
-</script>
-<div class="headbg">
-<div id="gaia">
-<span>
-<a href="#" id="projects-dropdown" onclick="return false;"><u>My favorites</u> <small>&#9660;</small></a>
- | <a href="https://www.google.com/accounts/ServiceLogin?service=code&amp;ltmpl=phosting&amp;continue=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D5&amp;followup=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D5" onclick="_CS_click('/gb/ph/signin');"><u>Sign in</u></a>
-</span>
-</div>
-<div class="gbh" style="left: 0pt;"></div>
-<div class="gbh" style="right: 0pt;"></div>
-<div style="height: 1px"></div>
-<!--[if lte IE 7]>
-<div style="text-align:center;">
-Your version of Internet Explorer is not supported. Try a browser that
-contributes to open source, such as <a href="http://www.firefox.com">Firefox</a>,
-<a href="http://www.google.com/chrome">Google Chrome</a>, or
-<a href="http://code.google.com/chrome/chromeframe/">Google Chrome Frame</a>.
-</div>
-<![endif]-->
-<table style="padding:0px; margin: 0px 0px 10px 0px; width:100%" cellpadding="0" cellspacing="0" itemscope="itemscope" itemtype="http://schema.org/CreativeWork">
-<tr style="height: 58px;">
-<td id="plogo">
-<link itemprop="url" href="/p/allura-google-importer" />
-<a href="/p/allura-google-importer/">
-<img src="/p/allura-google-importer/logo?cct=1374769571" alt="Logo" itemprop="image" />
-</a>
-</td>
-<td style="padding-left: 0.5em">
-<div id="pname">
-<a href="/p/allura-google-importer/"><span itemprop="name">allura-google-importer</span></a>
-</div>
-<div id="psum">
-<a id="project_summary_link" href="/p/allura-google-importer/"><span itemprop="description">Import Google Code projects to an Allura forge</span></a>
-</div>
-</td>
-<td style="white-space:nowrap;text-align:right; vertical-align:bottom;">
-<form action="/hosting/search">
-<input size="30" name="q" value="" type="text" />
-<input type="submit" name="projectsearch" value="Search projects" />
-</form>
-</td></tr>
-</table>
-</div>
-<div id="mt" class="gtb">
-<a href="/p/allura-google-importer/" class="tab ">Project&nbsp;Home</a>
-<a href="/p/allura-google-importer/wiki/TestPage?tm=6" class="tab ">Wiki</a>
-<a href="/p/allura-google-importer/issues/list" class="tab active">Issues</a>
-<a href="/p/allura-google-importer/source/checkout" class="tab ">Source</a>
-<div class="gtbc"></div>
-</div>
-<table cellspacing="0" cellpadding="0" width="100%" align="center" border="0" class="st">
-<tr>
-<td class="subt">
-<div class="issueDetail">
-<div class="isf">
-<span class="inIssueEntry">
-<a class="buttonify" href="entry" onclick="return _newIssuePrompt();">New issue</a>
-</span> &nbsp;
-
- <span class="inIssueList">
-<span>Search</span>
-</span><form action="list" method="GET" style="display:inline">
-<select id="can" name="can">
-<option disabled="disabled">Search within:</option>
-<option value="1">&nbsp;All issues</option>
-<option value="2" selected="selected">&nbsp;Open issues</option>
-<option value="6">&nbsp;New issues</option>
-<option value="7">&nbsp;Issues to verify</option>
-</select>
-<span>for</span>
-<span id="qq"><input type="text" size="38" id="searchq" name="q" value="" autocomplete="off" onkeydown="_blurOnEsc(event)" /></span>
-<span id="search_colspec"><input type="hidden" name="colspec" value="ID Type Status Priority Milestone Owner Summary" /></span>
-<input type="hidden" name="cells" value="tiles" />
-<input type="submit" value="Search" />
-</form>
- &nbsp;
- <span class="inIssueAdvSearch">
-<a href="advsearch">Advanced search</a>
-</span> &nbsp;
- <span class="inIssueSearchTips">
-<a href="searchtips">Search tips</a>
-</span> &nbsp;
- <span class="inIssueSubscriptions">
-<a href="/p/allura-google-importer/issues/subscriptions">Subscriptions</a>
-</span>
-</div>
-</div>
-</td>
-<td align="right" valign="top" class="bevel-right"></td>
-</tr>
-</table>
-<script type="text/javascript">
- var cancelBubble = false;
- function _go(url) { document.location = url; }
-</script>
-<div id="maincol">
-<div id="color_control" class="">
-<div id="issueheader">
-<table cellpadding="0" cellspacing="0" width="100%"><tbody>
-<tr>
-<td class="vt h3" nowrap="nowrap" style="padding:0 5px">
-
-
- Issue <a href="detail?id=5">5</a>:
- </td>
-<td width="90%" class="vt">
-<span class="h3">Empty Issue</span>
-</td>
-<td>
-<div class="pagination">
-<a href="../../allura-google-importer/issues/detail?id=4" title="Prev">&lsaquo; Prev</a>
- 5 of 5
-
- </div>
-</td>
-</tr>
-<tr>
-<td></td>
-<td nowrap="nowrap">
-
-
- 1 person starred this issue and may be notified of changes.
-
-
-
- </td>
-<td align="center" nowrap="nowrap">
-<a href="http://code.google.com/p/allura-google-importer/issues/list?cursor=allura-google-importer%3A5">Back to list</a>
-</td>
-</tr>
-</tbody></table>
-</div>
-<table width="100%" cellpadding="0" cellspacing="0" border="0" class="issuepage" id="meta-container">
-<tbody class="collapse">
-<tr>
-<td id="issuemeta">
-<div id="meta-float">
-<table cellspacing="0" cellpadding="0">
-<tr><th align="left">Status:&nbsp;</th>
-<td width="100%">
-
-
- ----
-
-
- </td>
-</tr>
-<tr><th align="left">Owner:&nbsp;</th><td>
-
-
- ----
-
-
- </td>
-</tr>
-<tr><td colspan="2">
-</td></tr>
-</table>
-<div class="rel_issues">
-</div>
-<br /><br />
-<div style="white-space:nowrap"><a href="https://www.google.com/accounts/ServiceLogin?service=code&amp;ltmpl=phosting&amp;continue=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D5&amp;followup=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D5">Sign in</a> to add a comment</div>
-</div>&nbsp;
- </td>
-<td class="vt issuedescription" width="100%" id="cursorarea">
-<div class="cursor_off vt issuedescription" id="hc0">
-<div class="author">
-<span class="role_label">Project Member</span>
- Reported by
-
-
- <span class="userlink">john...@gmail.com</span>,
- <span class="date" title="Thu Aug  8 14:56:23 2013">Today (15 minutes ago)</span>
-</div>
-<pre>
-Empty
-</pre>
-</div>
-</td>
-</tr>
-<tr>
-<td></td>
-<td class="vt issuecomment">
-<span class="indicator">&#9658;</span> <a href="https://www.google.com/accounts/ServiceLogin?service=code&amp;ltmpl=phosting&amp;continue=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D5&amp;followup=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D5">Sign in</a> to add a comment
- </td>
-</tr>
-</tbody>
-</table>
-<br />
-<script type="text/javascript" src="http://www.gstatic.com/codesite/ph/3783617020303179221/js/dit_scripts.js"></script>
-</div>
-<form name="delcom" action="delComment.do?q=&amp;can=2&amp;groupby=&amp;sort=&amp;colspec=ID+Type+Status+Priority+Milestone+Owner+Summary" method="POST">
-<input type="hidden" name="sequence_num" value="" />
-<input type="hidden" name="mode" value="" />
-<input type="hidden" name="id" value="5" />
-<input type="hidden" name="token" value="" />
-</form>
-<div id="helparea"></div>
-<script type="text/javascript">
- _onload();
- function delComment(sequence_num, delete_mode) {
- var f = document.forms["delcom"];
- f.sequence_num.value = sequence_num;
- f.mode.value = delete_mode;
-
- f.submit();
- return false;
- }
-
- _floatMetadata();
-</script>
-<script type="text/javascript" src="http://www.gstatic.com/codesite/ph/3783617020303179221/js/kibbles.js"></script>
-<script type="text/javascript">
- _setupKibblesOnDetailPage(
- 'http://code.google.com/p/allura-google-importer/issues/list?cursor\x3dallura-google-importer%3A5',
- '/p/allura-google-importer/issues/entry',
- '../../allura-google-importer/issues/detail?id\x3d4',
- '',
- '', 'allura-google-importer', 5,
- false, false, codesite_token);
-</script>
-<script type="text/javascript" src="http://www.gstatic.com/codesite/ph/3783617020303179221/js/ph_core.js"></script>
-</div>
-<div id="footer" dir="ltr">
-<div class="text">
-<a href="/projecthosting/terms.html">Terms</a> -
- <a href="http://www.google.com/privacy.html">Privacy</a> -
- <a href="/p/support/">Project Hosting Help</a>
-</div>
-</div>
-<div class="hostedBy" style="margin-top: -20px;">
-<span style="vertical-align: top;">Powered by <a href="http://code.google.com/projecthosting/">Google Project Hosting</a></span>
-</div>
-</body>
-</html>