| Index: chrome/common/extensions/docs/server2/path_canonicalizer.py
|
| diff --git a/chrome/common/extensions/docs/server2/path_canonicalizer.py b/chrome/common/extensions/docs/server2/path_canonicalizer.py
|
| index 8b5f77c03d09f82ef7bcecdcd179fc279f25f948..b4498a7f611cd02c5c965a9467252143863ab287 100644
|
| --- a/chrome/common/extensions/docs/server2/path_canonicalizer.py
|
| +++ b/chrome/common/extensions/docs/server2/path_canonicalizer.py
|
| @@ -2,48 +2,106 @@
|
| # Use of this source code is governed by a BSD-style license that can be
|
| # found in the LICENSE file.
|
|
|
| +import logging
|
| import os
|
| +import posixpath
|
| +import traceback
|
| +
|
| +from branch_utility import BranchUtility
|
| +from file_system import FileNotFoundError
|
| from third_party.json_schema_compiler.model import UnixName
|
| import svn_constants
|
|
|
| +def _SimplifyFileName(file_name):
|
| + return (posixpath.splitext(file_name)[0]
|
| + .lower()
|
| + .replace('.', '')
|
| + .replace('-', '')
|
| + .replace('_', ''))
|
| +
|
| class PathCanonicalizer(object):
|
| '''Transforms paths into their canonical forms. Since the dev server has had
|
| many incarnations - e.g. there didn't use to be apps/ - there may be old
|
| paths lying around the webs. We try to redirect those to where they are now.
|
| '''
|
| - def __init__(self, channel, compiled_fs_factory):
|
| - self._channel = channel
|
| - self._identity_fs = compiled_fs_factory.CreateIdentity(PathCanonicalizer)
|
| + def __init__(self, compiled_fs_factory):
|
| + # Map of simplified API names (for typo detection) to their real paths.
|
| + def make_public_apis(_, file_names):
|
| + return dict((_SimplifyFileName(name), name) for name in file_names)
|
| + self._public_apis = compiled_fs_factory.Create(make_public_apis,
|
| + PathCanonicalizer)
|
|
|
| def Canonicalize(self, path):
|
| - starts_with_channel, path_without_channel = (False, path)
|
| - if path.startswith('%s/' % self._channel):
|
| - starts_with_channel, path_without_channel = (
|
| - True, path[len(self._channel) + 1:])
|
| -
|
| - if any(path.startswith(prefix)
|
| - for prefix in ('extensions/', 'apps/', 'static/')):
|
| - return path
|
| -
|
| - if '/' in path_without_channel or path_without_channel == '404.html':
|
| - return path
|
| -
|
| - apps_templates = self._identity_fs.GetFromFileListing(
|
| - '/'.join((svn_constants.PUBLIC_TEMPLATE_PATH, 'apps')))
|
| - extensions_templates = self._identity_fs.GetFromFileListing(
|
| - '/'.join((svn_constants.PUBLIC_TEMPLATE_PATH, 'extensions')))
|
| -
|
| - if self._channel is None or not starts_with_channel:
|
| - apps_path = 'apps/%s' % path_without_channel
|
| - extensions_path = 'extensions/%s' % path_without_channel
|
| + '''Returns the canonical path for |path|, and whether that path is a
|
| + permanent canonicalisation (e.g. when we redirect from a channel to a
|
| + channel-less URL) or temporary (e.g. when we redirect from an apps-only API
|
| + to an extensions one - we may at some point enable it for extensions).
|
| + '''
|
| + class ReturnType(object):
|
| + def __init__(self, path, permanent):
|
| + self.path = path
|
| + self.permanent = permanent
|
| +
|
| + # Catch incorrect comparisons by disabling ==/!=.
|
| + def __eq__(self, _): raise NotImplementedError()
|
| + def __ne__(self, _): raise NotImplementedError()
|
| +
|
| + # Strip any channel info off it. There are no channels anymore.
|
| + for channel_name in BranchUtility.GetAllChannelNames():
|
| + channel_prefix = channel_name + '/'
|
| + if path.startswith(channel_prefix):
|
| + # Redirect now so that we can set the permanent-redirect bit. Channel
|
| + # redirects are the only things that should be permanent redirects;
|
| + # anything else *could* change, so is temporary.
|
| + return ReturnType(path[len(channel_prefix):], True)
|
| +
|
| + # No further work needed for static.
|
| + if path.startswith('static/'):
|
| + return ReturnType(path, False)
|
| +
|
| + # People go to just "extensions" or "apps". Redirect to the directory.
|
| + if path in ('extensions', 'apps'):
|
| + return ReturnType(path + '/', False)
|
| +
|
| + # The rest of this function deals with trying to figure out what API page
|
| + # for extensions/apps to redirect to, if any. We see a few different cases
|
| + # here:
|
| + # - Unqualified names ("browserAction.html"). These are easy to resolve;
|
| + # figure out whether it's an extension or app API and redirect.
|
| + # - but what if it's both? Well, assume extensions. Maybe later we can
|
| + # check analytics and see which is more popular.
|
| + # - Wrong names ("apps/browserAction.html"). This really does happen,
|
| + # damn it, so do the above logic but record which is the default.
|
| + if path.startswith(('extensions/', 'apps/')):
|
| + default_platform, reference_path = path.split('/', 1)
|
| + else:
|
| + default_platform, reference_path = ('extensions', path)
|
| +
|
| + try:
|
| + apps_public = self._public_apis.GetFromFileListing(
|
| + '/'.join((svn_constants.PUBLIC_TEMPLATE_PATH, 'apps')))
|
| + extensions_public = self._public_apis.GetFromFileListing(
|
| + '/'.join((svn_constants.PUBLIC_TEMPLATE_PATH, 'extensions')))
|
| + except FileNotFoundError:
|
| + # Probably offline.
|
| + logging.warning(traceback.format_exc())
|
| + return ReturnType(path, False)
|
| +
|
| + simple_reference_path = _SimplifyFileName(reference_path)
|
| + apps_path = apps_public.get(simple_reference_path)
|
| + extensions_path = extensions_public.get(simple_reference_path)
|
| +
|
| + if apps_path is None:
|
| + if extensions_path is None:
|
| + # No idea. Just return the original path. It'll probably 404.
|
| + pass
|
| + else:
|
| + path = 'extensions/%s' % extensions_path
|
| else:
|
| - apps_path = '%s/apps/%s' % (self._channel, path_without_channel)
|
| - extensions_path = '%s/extensions/%s' % (self._channel,
|
| - path_without_channel)
|
| -
|
| - unix_path = UnixName(os.path.splitext(path_without_channel)[0])
|
| - if unix_path in extensions_templates:
|
| - return extensions_path
|
| - if unix_path in apps_templates:
|
| - return apps_path
|
| - return extensions_path
|
| + if extensions_path is None:
|
| + path = 'apps/%s' % apps_path
|
| + else:
|
| + assert apps_path == extensions_path
|
| + path = '%s/%s' % (default_platform, apps_path)
|
| +
|
| + return ReturnType(path, False)
|
|
|