Chromium Code Reviews| 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 c01973cdc365e0d4a489daf03a908e8295487412..3c566e337209735eeafbf81f030f1ba9dc3ceafa 100644 |
| --- a/chrome/common/extensions/docs/server2/path_canonicalizer.py |
| +++ b/chrome/common/extensions/docs/server2/path_canonicalizer.py |
| @@ -4,47 +4,103 @@ |
| 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 {_SimplifyFileName(name): name for name in file_names} |
|
cduvall
2013/05/15 00:50:50
use dict((...
not at google - send to devlin
2013/05/15 01:26:50
Done.
|
| + 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() |
|
cduvall
2013/05/15 00:50:50
these need to take another argument or you get a T
not at google - send to devlin
2013/05/15 01:26:50
ah. thanks.
|
| + 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 any(path.startswith(prefix) for prefix in ('extensions/', 'apps/')): |
|
cduvall
2013/05/15 00:50:50
i believe you can do:
path.startswith(('extensions
not at google - send to devlin
2013/05/15 01:26:50
Done.
|
| + default_platform, reference_path = path.split('/', 1) |
| 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 |
| + 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: |
| + 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) |