Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import logging | 5 import logging |
| 6 import os | 6 import os |
| 7 import posixpath | |
| 8 import traceback | |
| 9 | |
| 10 from branch_utility import BranchUtility | |
| 11 from file_system import FileNotFoundError | |
| 7 from third_party.json_schema_compiler.model import UnixName | 12 from third_party.json_schema_compiler.model import UnixName |
| 8 import svn_constants | 13 import svn_constants |
| 9 | 14 |
| 15 def _SimplifyFileName(file_name): | |
| 16 return (posixpath.splitext(file_name)[0] | |
| 17 .lower() | |
| 18 .replace('.', '') | |
| 19 .replace('-', '') | |
| 20 .replace('_', '')) | |
| 21 | |
| 10 class PathCanonicalizer(object): | 22 class PathCanonicalizer(object): |
| 11 '''Transforms paths into their canonical forms. Since the dev server has had | 23 '''Transforms paths into their canonical forms. Since the dev server has had |
| 12 many incarnations - e.g. there didn't use to be apps/ - there may be old | 24 many incarnations - e.g. there didn't use to be apps/ - there may be old |
| 13 paths lying around the webs. We try to redirect those to where they are now. | 25 paths lying around the webs. We try to redirect those to where they are now. |
| 14 ''' | 26 ''' |
| 15 def __init__(self, channel, compiled_fs_factory): | 27 def __init__(self, compiled_fs_factory): |
| 16 self._channel = channel | 28 # Map of simplified API names (for typo detection) to their real paths. |
| 17 self._identity_fs = compiled_fs_factory.CreateIdentity(PathCanonicalizer) | 29 def make_public_apis(_, file_names): |
| 30 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.
| |
| 31 self._public_apis = compiled_fs_factory.Create(make_public_apis, | |
| 32 PathCanonicalizer) | |
| 18 | 33 |
| 19 def Canonicalize(self, path): | 34 def Canonicalize(self, path): |
| 20 starts_with_channel, path_without_channel = (False, path) | 35 '''Returns the canonical path for |path|, and whether that path is a |
| 21 if path.startswith('%s/' % self._channel): | 36 permanent canonicalisation (e.g. when we redirect from a channel to a |
| 22 starts_with_channel, path_without_channel = ( | 37 channel-less URL) or temporary (e.g. when we redirect from an apps-only API |
| 23 True, path[len(self._channel) + 1:]) | 38 to an extensions one - we may at some point enable it for extensions). |
| 39 ''' | |
| 40 class ReturnType(object): | |
| 41 def __init__(self, path, permanent): | |
| 42 self.path = path | |
| 43 self.permanent = permanent | |
| 44 # Catch incorrect comparisons by disabling ==/!=. | |
| 45 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.
| |
| 46 def __ne__(self): raise NotImplementedError() | |
| 24 | 47 |
| 25 if any(path.startswith(prefix) | 48 # Strip any channel info off it. There are no channels anymore. |
| 26 for prefix in ('extensions/', 'apps/', 'static/')): | 49 for channel_name in BranchUtility.GetAllChannelNames(): |
| 27 return path | 50 channel_prefix = channel_name + '/' |
| 51 if path.startswith(channel_prefix): | |
| 52 # Redirect now so that we can set the permanent-redirect bit. Channel | |
| 53 # redirects are the only things that should be permanent redirects; | |
| 54 # anything else *could* change, so is temporary. | |
| 55 return ReturnType(path[len(channel_prefix):], True) | |
| 28 | 56 |
| 29 if '/' in path_without_channel or path_without_channel == '404.html': | 57 # No further work needed for static. |
| 30 return path | 58 if path.startswith('static/'): |
| 59 return ReturnType(path, False) | |
| 31 | 60 |
| 32 apps_templates = self._identity_fs.GetFromFileListing( | 61 # People go to just "extensions" or "apps". Redirect to the directory. |
| 33 '/'.join((svn_constants.PUBLIC_TEMPLATE_PATH, 'apps'))) | 62 if path in ('extensions', 'apps'): |
| 34 extensions_templates = self._identity_fs.GetFromFileListing( | 63 return ReturnType(path + '/', False) |
| 35 '/'.join((svn_constants.PUBLIC_TEMPLATE_PATH, 'extensions'))) | |
| 36 | 64 |
| 37 if self._channel is None or not starts_with_channel: | 65 # The rest of this function deals with trying to figure out what API page |
| 38 apps_path = 'apps/%s' % path_without_channel | 66 # for extensions/apps to redirect to, if any. We see a few different cases |
| 39 extensions_path = 'extensions/%s' % path_without_channel | 67 # here: |
| 68 # - Unqualified names ("browserAction.html"). These are easy to resolve; | |
| 69 # figure out whether it's an extension or app API and redirect. | |
| 70 # - but what if it's both? Well, assume extensions. Maybe later we can | |
| 71 # check analytics and see which is more popular. | |
| 72 # - Wrong names ("apps/browserAction.html"). This really does happen, | |
| 73 # damn it, so do the above logic but record which is the default. | |
| 74 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.
| |
| 75 default_platform, reference_path = path.split('/', 1) | |
| 40 else: | 76 else: |
| 41 apps_path = '%s/apps/%s' % (self._channel, path_without_channel) | 77 default_platform, reference_path = ('extensions', path) |
| 42 extensions_path = '%s/extensions/%s' % (self._channel, | |
| 43 path_without_channel) | |
| 44 | 78 |
| 45 unix_path = UnixName(os.path.splitext(path_without_channel)[0]) | 79 try: |
| 46 if unix_path in extensions_templates: | 80 apps_public = self._public_apis.GetFromFileListing( |
| 47 return extensions_path | 81 '/'.join((svn_constants.PUBLIC_TEMPLATE_PATH, 'apps'))) |
| 48 if unix_path in apps_templates: | 82 extensions_public = self._public_apis.GetFromFileListing( |
| 49 return apps_path | 83 '/'.join((svn_constants.PUBLIC_TEMPLATE_PATH, 'extensions'))) |
| 50 return extensions_path | 84 except FileNotFoundError: |
| 85 # Probably offline. | |
| 86 logging.warning(traceback.format_exc()) | |
| 87 return ReturnType(path, False) | |
| 88 | |
| 89 simple_reference_path = _SimplifyFileName(reference_path) | |
| 90 apps_path = apps_public.get(simple_reference_path) | |
| 91 extensions_path = extensions_public.get(simple_reference_path) | |
| 92 | |
| 93 if apps_path is None: | |
| 94 if extensions_path is None: | |
| 95 # No idea. Just return the original path. It'll probably 404. | |
| 96 pass | |
| 97 else: | |
| 98 path = 'extensions/%s' % extensions_path | |
| 99 else: | |
| 100 if extensions_path is None: | |
| 101 path = 'apps/%s' % apps_path | |
| 102 else: | |
| 103 assert apps_path == extensions_path | |
| 104 path = '%s/%s' % (default_platform, apps_path) | |
| 105 | |
| 106 return ReturnType(path, False) | |
| OLD | NEW |