summaryrefslogtreecommitdiff
path: root/www-client
diff options
context:
space:
mode:
authorV3n3RiX <venerix@redcorelinux.org>2018-04-20 19:27:12 +0100
committerV3n3RiX <venerix@redcorelinux.org>2018-04-20 19:27:12 +0100
commit56d0c8205c9fe7b4cff71030722e1a553aac006d (patch)
treedcde90176ac9f080bc5adeca3033a29c3900d593 /www-client
parentb9e1b6165fc952c21eb1acde9a6d2d7ddbd2bc27 (diff)
"www-client/chromium : add-missing-blink-tools, see : https://groups.google.com/a/chromium.org/forum/#!msg/chromium-packagers/So-ojMYOQdI/K66hndtdCAAJ"
Diffstat (limited to 'www-client')
-rw-r--r--www-client/chromium/chromium-66.0.3359.117-r2.ebuild (renamed from www-client/chromium/chromium-66.0.3359.117-r1.ebuild)1
-rw-r--r--www-client/chromium/files/add-missing-blink-tools.patch1071
2 files changed, 1072 insertions, 0 deletions
diff --git a/www-client/chromium/chromium-66.0.3359.117-r1.ebuild b/www-client/chromium/chromium-66.0.3359.117-r2.ebuild
index 7894a2e8..8fb24994 100644
--- a/www-client/chromium/chromium-66.0.3359.117-r1.ebuild
+++ b/www-client/chromium/chromium-66.0.3359.117-r2.ebuild
@@ -154,6 +154,7 @@ PATCHES=(
"${FILESDIR}/chromium-clang-r4.patch"
"${FILESDIR}/chromium-ffmpeg-r1.patch"
"${FILESDIR}/chromium-ffmpeg-clang.patch"
+ "${FILESDIR}/add-missing-blink-tools.patch"
)
pre_build_checks() {
diff --git a/www-client/chromium/files/add-missing-blink-tools.patch b/www-client/chromium/files/add-missing-blink-tools.patch
new file mode 100644
index 00000000..4eddd8c7
--- /dev/null
+++ b/www-client/chromium/files/add-missing-blink-tools.patch
@@ -0,0 +1,1071 @@
+Description: add back contents of third-party/blink/tools that went missing in the source tarball for 66.0.3359.106
+Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=832283
+
+--- /dev/null
++++ b/third_party/blink/tools/OWNERS
+@@ -0,0 +1 @@
++file://third_party/WebKit/Tools/OWNERS
+--- /dev/null
++++ b/third_party/blink/tools/blinkpy/__init__.py
+@@ -0,0 +1,3 @@
++# Copyright 2017 The Chromium Authors. All rights reserved.
++# Use of this source code is governed by a BSD-style license that can be
++# found in the LICENSE file.
+--- /dev/null
++++ b/third_party/blink/tools/blinkpy/common/__init__.py
+@@ -0,0 +1,3 @@
++# Copyright 2017 The Chromium Authors. All rights reserved.
++# Use of this source code is governed by a BSD-style license that can be
++# found in the LICENSE file.
+--- /dev/null
++++ b/third_party/blink/tools/blinkpy/common/name_style_converter.py
+@@ -0,0 +1,128 @@
++# Copyright 2017 The Chromium Authors. All rights reserved.
++# Use of this source code is governed by a BSD-style license that can be
++# found in the LICENSE file.
++
++# pylint: disable=import-error,print-statement,relative-import
++
++import re
++
++SPECIAL_TOKENS = [
++ # This list should be sorted by length.
++ 'CString',
++ 'Float32',
++ 'Float64',
++ 'Base64',
++ 'IFrame',
++ 'Latin1',
++ 'PlugIn',
++ 'SQLite',
++ 'Uint16',
++ 'Uint32',
++ 'WebGL2',
++ 'ASCII',
++ 'CType',
++ 'DList',
++ 'Int16',
++ 'Int32',
++ 'MPath',
++ 'OList',
++ 'TSpan',
++ 'UList',
++ 'UTF16',
++ 'Uint8',
++ 'WebGL',
++ 'XPath',
++ 'ETC1',
++ 'HTML',
++ 'Int8',
++ 'S3TC',
++ 'SPv2',
++ 'UTF8',
++ 'API',
++ 'CSS',
++ 'DOM',
++ 'EXT',
++ 'RTC',
++ 'SVG',
++ '2D',
++ 'AX',
++ 'V0',
++ 'V8',
++]
++
++MATCHING_EXPRESSION = '((?:[A-Z][a-z]+)|[0-9]D?$)'
++
++
++class SmartTokenizer(object):
++ """Detects special cases that are not easily discernible without additional
++ knowledge, such as recognizing that in SVGSVGElement, the first two SVGs
++ are separate tokens, but WebGL is one token."""
++
++ def __init__(self, name):
++ self.remaining = name
++
++ def tokenize(self):
++ name = self.remaining
++ tokens = []
++ while len(name) > 0:
++ matched_token = None
++ for token in SPECIAL_TOKENS:
++ if name.startswith(token):
++ matched_token = token
++ break
++ if not matched_token:
++ match = re.search(MATCHING_EXPRESSION, name)
++ if not match:
++ matched_token = name
++ elif match.start(0) != 0:
++ matched_token = name[:match.start(0)]
++ else:
++ matched_token = match.group(0)
++ tokens.append(name[:len(matched_token)])
++ name = name[len(matched_token):]
++ return tokens
++
++
++class NameStyleConverter(object):
++ """Converts names from camelCase to various other styles.
++ """
++
++ def __init__(self, name):
++ self.tokens = self.tokenize(name)
++
++ def tokenize(self, name):
++ tokenizer = SmartTokenizer(name)
++ return tokenizer.tokenize()
++
++ def to_snake_case(self):
++ """Snake case is the file and variable name style per Google C++ Style
++ Guide:
++ https://google.github.io/styleguide/cppguide.html#Variable_Names
++
++ Also known as the hacker case.
++ https://en.wikipedia.org/wiki/Snake_case
++ """
++ return '_'.join([token.lower() for token in self.tokens])
++
++ def to_upper_camel_case(self):
++ """Upper-camel case is the class and function name style per
++ Google C++ Style Guide:
++ https://google.github.io/styleguide/cppguide.html#Function_Names
++
++ Also known as the PascalCase.
++ https://en.wikipedia.org/wiki/Camel_case.
++ """
++ return ''.join([token[0].upper() + token[1:] for token in self.tokens])
++
++ def to_macro_case(self):
++ """Macro case is the macro name style per Google C++ Style Guide:
++ https://google.github.io/styleguide/cppguide.html#Macro_Names
++ """
++ return '_'.join([token.upper() for token in self.tokens])
++
++ def to_all_cases(self):
++ return {
++ 'snake_case': self.to_snake_case(),
++ 'upper_camel_case': self.to_upper_camel_case(),
++ 'macro_case': self.to_macro_case(),
++ }
+--- /dev/null
++++ b/third_party/blink/tools/blinkpy/common/name_style_converter_test.py
+@@ -0,0 +1,178 @@
++# Copyright 2017 The Chromium Authors. All rights reserved.
++# Use of this source code is governed by a BSD-style license that can be
++# found in the LICENSE file.
++
++# pylint: disable=import-error,print-statement,relative-import,protected-access
++
++"""Unit tests for name_style_converter.py."""
++
++import unittest
++
++from name_style_converter import NameStyleConverter
++from name_style_converter import SmartTokenizer
++
++
++class SmartTokenizerTest(unittest.TestCase):
++ def test_simple_cases(self):
++ tokenizer = SmartTokenizer('foo')
++ self.assertEqual(tokenizer.tokenize(), ['foo'])
++
++ tokenizer = SmartTokenizer('fooBar')
++ self.assertEqual(tokenizer.tokenize(), ['foo', 'Bar'])
++
++ tokenizer = SmartTokenizer('fooBarBaz')
++ self.assertEqual(tokenizer.tokenize(), ['foo', 'Bar', 'Baz'])
++
++ tokenizer = SmartTokenizer('Baz')
++ self.assertEqual(tokenizer.tokenize(), ['Baz'])
++
++ tokenizer = SmartTokenizer('')
++ self.assertEqual(tokenizer.tokenize(), [])
++
++ tokenizer = SmartTokenizer('FOO')
++ self.assertEqual(tokenizer.tokenize(), ['FOO'])
++
++ tokenizer = SmartTokenizer('foo2')
++ self.assertEqual(tokenizer.tokenize(), ['foo', '2'])
++
++ def test_tricky_cases(self):
++ tokenizer = SmartTokenizer('XMLHttpRequest')
++ self.assertEqual(tokenizer.tokenize(), ['XML', 'Http', 'Request'])
++
++ tokenizer = SmartTokenizer('HTMLElement')
++ self.assertEqual(tokenizer.tokenize(), ['HTML', 'Element'])
++
++ tokenizer = SmartTokenizer('WebGLRenderingContext')
++ self.assertEqual(tokenizer.tokenize(),
++ ['WebGL', 'Rendering', 'Context'])
++
++ tokenizer = SmartTokenizer('CanvasRenderingContext2D')
++ self.assertEqual(tokenizer.tokenize(),
++ ['Canvas', 'Rendering', 'Context', '2D'])
++ tokenizer = SmartTokenizer('CanvasRenderingContext2DAPITest')
++ self.assertEqual(tokenizer.tokenize(),
++ ['Canvas', 'Rendering', 'Context', '2D', 'API', 'Test'])
++
++ tokenizer = SmartTokenizer('SVGSVGElement')
++ self.assertEqual(tokenizer.tokenize(), ['SVG', 'SVG', 'Element'])
++
++ tokenizer = SmartTokenizer('CanvasRenderingContext2D')
++ self.assertEqual(tokenizer.tokenize(), ['Canvas', 'Rendering', 'Context', '2D'])
++
++ tokenizer = SmartTokenizer('CSSURLImageValue')
++ self.assertEqual(tokenizer.tokenize(), ['CSS', 'URL', 'Image', 'Value'])
++ tokenizer = SmartTokenizer('CSSPropertyAPID')
++ self.assertEqual(tokenizer.tokenize(), ['CSS', 'Property', 'API', 'D'])
++ tokenizer = SmartTokenizer('AXARIAGridCell')
++ self.assertEqual(tokenizer.tokenize(), ['AX', 'ARIA', 'Grid', 'Cell'])
++
++ tokenizer = SmartTokenizer('CDATASection')
++ self.assertEqual(tokenizer.tokenize(), ['CDATA', 'Section'])
++
++ tokenizer = SmartTokenizer('ASCIICType')
++ self.assertEqual(tokenizer.tokenize(), ['ASCII', 'CType'])
++ tokenizer = SmartTokenizer('CString')
++ self.assertEqual(tokenizer.tokenize(), ['CString'])
++
++ tokenizer = SmartTokenizer('HTMLDListElement')
++ self.assertEqual(tokenizer.tokenize(), ['HTML', 'DList', 'Element'])
++ tokenizer = SmartTokenizer('HTMLOListElement')
++ self.assertEqual(tokenizer.tokenize(), ['HTML', 'OList', 'Element'])
++ tokenizer = SmartTokenizer('HTMLIFrameElement')
++ self.assertEqual(tokenizer.tokenize(), ['HTML', 'IFrame', 'Element'])
++ tokenizer = SmartTokenizer('HTMLPlugInElement')
++ self.assertEqual(tokenizer.tokenize(), ['HTML', 'PlugIn', 'Element'])
++
++ # No special handling for OptGroup, FieldSet, and TextArea.
++ tokenizer = SmartTokenizer('HTMLOptGroupElement')
++ self.assertEqual(tokenizer.tokenize(), ['HTML', 'Opt', 'Group', 'Element'])
++ tokenizer = SmartTokenizer('HTMLFieldSetElement')
++ self.assertEqual(tokenizer.tokenize(), ['HTML', 'Field', 'Set', 'Element'])
++ tokenizer = SmartTokenizer('HTMLTextAreaElement')
++ self.assertEqual(tokenizer.tokenize(), ['HTML', 'Text', 'Area', 'Element'])
++
++ tokenizer = SmartTokenizer('Path2D')
++ self.assertEqual(tokenizer.tokenize(), ['Path', '2D'])
++ tokenizer = SmartTokenizer('Point2D')
++ self.assertEqual(tokenizer.tokenize(), ['Point', '2D'])
++ tokenizer = SmartTokenizer('CanvasRenderingContext2DState')
++ self.assertEqual(tokenizer.tokenize(), ['Canvas', 'Rendering', 'Context', '2D', 'State'])
++
++ tokenizer = SmartTokenizer('RTCDTMFSender')
++ self.assertEqual(tokenizer.tokenize(), ['RTC', 'DTMF', 'Sender'])
++
++ tokenizer = SmartTokenizer('WebGLCompressedTextureS3TCsRGB')
++ self.assertEqual(tokenizer.tokenize(), ['WebGL', 'Compressed', 'Texture', 'S3TC', 'sRGB'])
++ tokenizer = SmartTokenizer('WebGL2CompressedTextureETC1')
++ self.assertEqual(tokenizer.tokenize(), ['WebGL2', 'Compressed', 'Texture', 'ETC1'])
++ tokenizer = SmartTokenizer('EXTsRGB')
++ self.assertEqual(tokenizer.tokenize(), ['EXT', 'sRGB'])
++
++ tokenizer = SmartTokenizer('SVGFEBlendElement')
++ self.assertEqual(tokenizer.tokenize(), ['SVG', 'FE', 'Blend', 'Element'])
++ tokenizer = SmartTokenizer('SVGMPathElement')
++ self.assertEqual(tokenizer.tokenize(), ['SVG', 'MPath', 'Element'])
++ tokenizer = SmartTokenizer('SVGTSpanElement')
++ self.assertEqual(tokenizer.tokenize(), ['SVG', 'TSpan', 'Element'])
++ tokenizer = SmartTokenizer('SVGURIReference')
++ self.assertEqual(tokenizer.tokenize(), ['SVG', 'URI', 'Reference'])
++
++ tokenizer = SmartTokenizer('UTF16TextIterator')
++ self.assertEqual(tokenizer.tokenize(), ['UTF16', 'Text', 'Iterator'])
++ tokenizer = SmartTokenizer('UTF8Decoder')
++ self.assertEqual(tokenizer.tokenize(), ['UTF8', 'Decoder'])
++ tokenizer = SmartTokenizer('Uint8Array')
++ self.assertEqual(tokenizer.tokenize(), ['Uint8', 'Array'])
++ tokenizer = SmartTokenizer('DOMWindowBase64')
++ self.assertEqual(tokenizer.tokenize(), ['DOM', 'Window', 'Base64'])
++ tokenizer = SmartTokenizer('TextCodecLatin1')
++ self.assertEqual(tokenizer.tokenize(), ['Text', 'Codec', 'Latin1'])
++ tokenizer = SmartTokenizer('V8BindingForCore')
++ self.assertEqual(tokenizer.tokenize(), ['V8', 'Binding', 'For', 'Core'])
++ tokenizer = SmartTokenizer('V8DOMRect')
++ self.assertEqual(tokenizer.tokenize(), ['V8', 'DOM', 'Rect'])
++
++ tokenizer = SmartTokenizer('V0InsertionPoint')
++ self.assertEqual(tokenizer.tokenize(), ['V0', 'Insertion', 'Point'])
++ tokenizer = SmartTokenizer('ShadowDOMV0Test')
++ self.assertEqual(tokenizer.tokenize(), ['Shadow', 'DOM', 'V0', 'Test'])
++ tokenizer = SmartTokenizer('ElementShadowV0')
++ self.assertEqual(tokenizer.tokenize(), ['Element', 'Shadow', 'V0'])
++ tokenizer = SmartTokenizer('StubChromeClientForSPv2')
++ self.assertEqual(tokenizer.tokenize(), ['Stub', 'Chrome', 'Client', 'For', 'SPv2'])
++
++ tokenizer = SmartTokenizer('SQLiteAuthorizer')
++ self.assertEqual(tokenizer.tokenize(), ['SQLite', 'Authorizer'])
++ tokenizer = SmartTokenizer('XPathEvaluator')
++ self.assertEqual(tokenizer.tokenize(), ['XPath', 'Evaluator'])
++
++ tokenizer = SmartTokenizer('IsXHTMLDocument')
++ self.assertEqual(tokenizer.tokenize(), ['Is', 'XHTML', 'Document'])
++
++ tokenizer = SmartTokenizer('Animation.idl')
++ self.assertEqual(tokenizer.tokenize(), ['Animation', '.idl'])
++
++
++class NameStyleConverterTest(unittest.TestCase):
++ def test_snake_case(self):
++ converter = NameStyleConverter('HTMLElement')
++ self.assertEqual(converter.to_snake_case(), 'html_element')
++
++ def test_upper_camel_case(self):
++ converter = NameStyleConverter('someSuperThing')
++ self.assertEqual(converter.to_upper_camel_case(), 'SomeSuperThing')
++
++ converter = NameStyleConverter('SVGElement')
++ self.assertEqual(converter.to_upper_camel_case(), 'SVGElement')
++
++ def test_macro_case(self):
++ converter = NameStyleConverter('WebGLBaz2D')
++ self.assertEqual(converter.to_macro_case(), 'WEBGL_BAZ_2D')
++
++ def test_all_cases(self):
++ converter = NameStyleConverter('SVGScriptElement')
++ self.assertEqual(converter.to_all_cases(), {
++ 'snake_case': 'svg_script_element',
++ 'upper_camel_case': 'SVGScriptElement',
++ 'macro_case': 'SVG_SCRIPT_ELEMENT',
++ })
+--- /dev/null
++++ b/third_party/blink/tools/compile_devtools_frontend.py
+@@ -0,0 +1,20 @@
++#!/usr/bin/env vpython
++# Copyright 2017 The Chromium Authors. All rights reserved.
++# Use of this source code is governed by a BSD-style license that can be
++# found in the LICENSE file.
++
++"""Compile DevTools frontend code with Closure compiler.
++
++This script wraps devtools/scripts/compile_frontend.py.
++DevTools bot kicks this script.
++"""
++
++import os
++import sys
++
++sys.path.append(os.path.join(
++ os.path.dirname(__file__), '..', '..', 'WebKit', 'Source', 'devtools', 'scripts'))
++import compile_frontend
++
++if __name__ == '__main__':
++ sys.exit(compile_frontend.main())
+--- /dev/null
++++ b/third_party/blink/tools/move_blink_source.py
+@@ -0,0 +1,615 @@
++#!/usr/bin/env vpython
++# Copyright 2017 The Chromium Authors. All rights reserved.
++# Use of this source code is governed by a BSD-style license that can be
++# found in the LICENSE file.
++
++"""Tool to move Blink source from third_party/WebKit to third_party/blink.
++
++See https://docs.google.com/document/d/1l3aPv1Wx__SpRkdOhvJz8ciEGigNT3wFKv78XiuW0Tw/edit?usp=sharing#heading=h.o225wrxp242h
++for the details.
++"""
++
++import argparse
++import logging
++import os
++import re
++import sys
++from functools import partial
++
++# Without abspath(), PathFinder can't find chromium_base correctly.
++sys.path.append(os.path.abspath(
++ os.path.join(os.path.dirname(__file__), '..', '..', '..',
++ 'third_party', 'WebKit', 'Tools', 'Scripts')))
++from blinkpy.common.name_style_converter import NameStyleConverter
++from plan_blink_move import plan_blink_move
++from plan_blink_move import relative_dest
++from webkitpy.common.checkout.git import Git
++from webkitpy.common.path_finder import get_chromium_src_dir
++from webkitpy.common.path_finder import get_scripts_dir
++from webkitpy.common.system.executive import Executive
++from webkitpy.common.system.executive import ScriptError
++from webkitpy.common.system.filesystem import FileSystem
++
++_log = logging.getLogger('move_blink_source')
++
++
++class FileType(object):
++ NONE = 0
++ BUILD = 1
++ BLINK_BUILD = 2
++ OWNERS = 3
++ DEPS = 4
++ MOJOM = 5
++ TYPEMAP = 6
++ BLINK_BUILD_PY = 7
++ LAYOUT_TESTS_WITH_MOJOM = 8
++
++ @staticmethod
++ def detect(path):
++ slash_dir, basename = os.path.split(path)
++ slash_dir = slash_dir.replace(os.path.sep, '/')
++ if basename == 'DEPS':
++ return FileType.DEPS
++ if basename == 'OWNERS':
++ return FileType.OWNERS
++ if basename.endswith('.mojom'):
++ return FileType.MOJOM
++ if basename.endswith('.typemap'):
++ return FileType.TYPEMAP
++ if basename.endswith('.py') and 'third_party/WebKit/Source/build' in slash_dir:
++ return FileType.BLINK_BUILD_PY
++ if basename.endswith(('.gn', '.gni')):
++ if 'third_party/WebKit' in path or 'third_party/blink' in slash_dir:
++ return FileType.BLINK_BUILD
++ if 'third_party' in slash_dir:
++ return FileType.NONE
++ return FileType.BUILD
++ if basename.endswith('.html') and re.search(
++ r'third_party/WebKit/LayoutTests/(geolocation-api|installedapp|' +
++ r'media/mediasession|payments|presentation|webshare)', slash_dir):
++ return FileType.LAYOUT_TESTS_WITH_MOJOM
++ return FileType.NONE
++
++
++class MoveBlinkSource(object):
++
++ def __init__(self, fs, options, repo_root):
++ self._fs = fs
++ self._options = options
++ _log.debug(options)
++ self._repo_root = repo_root
++
++ # The following fields are initialized in _create_basename_maps.
++ self._basename_map = None
++ self._basename_re = None
++ self._idl_generated_impl_headers = None
++ # _checked_in_header_re is used to distinguish checked-in header files
++ # and generated header files.
++ self._checked_in_header_re = None
++
++ self._updated_files = []
++
++ def update(self, apply_only=None):
++ """Updates contents of files affected by Blink source move.
++
++ Args:
++ apply_only: If it's None, updates all affected files. Otherwise,
++ it should be a set of file paths and this function updates
++ only the files in |apply_only|.
++ """
++ _log.info('Planning renaming ...')
++ file_pairs = plan_blink_move(self._fs, [])
++ _log.info('Will move %d files', len(file_pairs))
++
++ self._create_basename_maps(file_pairs)
++ dirs = self._update_file_content(apply_only)
++
++ # Updates #includes in files in directories with updated DEPS +
++ # third_party/WebKit/{Source,common,public}.
++ self._append_unless_upper_dir_exists(dirs, self._fs.join(self._repo_root, 'third_party', 'WebKit', 'Source'))
++ self._append_unless_upper_dir_exists(dirs, self._fs.join(self._repo_root, 'third_party', 'WebKit', 'common'))
++ self._append_unless_upper_dir_exists(dirs, self._fs.join(self._repo_root, 'third_party', 'WebKit', 'public'))
++ self._append_unless_upper_dir_exists(dirs, self._fs.join(self._repo_root, 'mojo', 'public', 'tools',
++ 'bindings', 'generators', 'cpp_templates'))
++ self._update_cpp_includes_in_directories(dirs, apply_only)
++
++ # Content update for individual files.
++ # The following is a list of tuples.
++ # Tuple: (<file path relative to repo root>, [replacement commands])
++ # Command: a callable object, or
++ # a tuple of (<original string>, <new string>).
++ file_replacement_list = [
++ ('DEPS',
++ [('src/third_party/WebKit/Source/devtools',
++ 'src/third_party/blink/renderer/devtools')]),
++ ('WATCHLISTS',
++ [('third_party/WebKit/Source', 'third_party/blink/renderer'),
++ ('third_party/WebKit/public', 'third_party/blink/renderer/public')]),
++ ('build/check_gn_headers_whitelist.txt',
++ [('third_party/WebKit/Source', 'third_party/blink/renderer'),
++ ('third_party/WebKit/public', 'third_party/blink/renderer/public'),
++ self._update_basename]),
++ ('testing/buildbot/gn_isolate_map.pyl',
++ [('third_party/WebKit/Source', 'third_party/blink/renderer')]),
++ ('third_party/WebKit/Source/BUILD.gn',
++ [('$root_gen_dir/third_party/WebKit',
++ '$root_gen_dir/third_party/blink/renderer')]),
++ ('third_party/WebKit/Source/config.gni',
++ [('snake_case_source_files = false',
++ 'snake_case_source_files = true')]),
++ ('third_party/WebKit/Source/core/css/CSSProperties.json5',
++ [self._update_basename]),
++ ('third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5',
++ [self._update_basename]),
++ ('third_party/WebKit/Source/core/css/ComputedStyleFieldAliases.json5',
++ [self._update_basename]),
++ ('third_party/WebKit/Source/core/html/parser/create-html-entity-table',
++ [self._update_basename]),
++ ('third_party/WebKit/Source/core/inspector/inspector_protocol_config.json',
++ [self._update_basename]),
++ ('third_party/WebKit/Source/core/probe/CoreProbes.json5',
++ [self._update_basename]),
++ ('third_party/WebKit/Source/core/testing/InternalSettings.h',
++ [('InternalSettingsGenerated.h', 'internal_settings_generated.h')]),
++ ('third_party/WebKit/Source/core/testing/Internals.cpp',
++ [('InternalRuntimeFlags.h', 'internal_runtime_flags.h')]),
++ ('third_party/WebKit/Source/platform/probe/PlatformProbes.json5',
++ [self._update_basename]),
++ ('third_party/WebKit/public/BUILD.gn',
++ [('$root_gen_dir/third_party/WebKit',
++ '$root_gen_dir/third_party/blink/renderer')]),
++ ('third_party/WebKit/public/blink_resources.grd',
++ [('../Source/', '../')]),
++ ('tools/android/eclipse/.classpath',
++ [('third_party/WebKit/public', 'third_party/blink/renderer/public')]),
++ ('tools/android/loading/cloud/backend/deploy.sh',
++ [('third_party/WebKit/Source', 'third_party/blink/renderer')]),
++ ('tools/android/loading/emulation_unittest.py',
++ [('third_party/WebKit/Source', 'third_party/blink/renderer')]),
++ ('tools/android/loading/options.py',
++ [('third_party/WebKit/Source', 'third_party/blink/renderer')]),
++ ('tools/android/loading/request_track.py',
++ [('third_party/WebKit/Source', 'third_party/blink/renderer')]),
++ ('tools/gritsettings/resource_ids',
++ [('third_party/WebKit/public', 'third_party/blink/renderer/public'),
++ ('third_party/WebKit/Source', 'third_party/blink/renderer')]),
++ ('tools/metrics/actions/extract_actions.py',
++ [('third_party/WebKit/Source', 'third_party/blink/renderer')]),
++ ('tools/metrics/histograms/update_editor_commands.py',
++ [('third_party/WebKit/Source/core/editing/EditorCommand.cpp',
++ 'third_party/blink/renderer/core/editing/editor_command.cc')]),
++ ('tools/metrics/histograms/update_use_counter_css.py',
++ [('third_party/WebKit/Source/core/frame/UseCounter.cpp',
++ 'third_party/blink/renderer/core/frame/use_counter.cc')]),
++ ('tools/metrics/histograms/update_use_counter_feature_enum.py',
++ [('third_party/WebKit/public', 'third_party/blink/renderer/public')]),
++ ]
++ for file_path, replacement_list in file_replacement_list:
++ if not apply_only or file_path in apply_only:
++ self._update_single_file_content(file_path, replacement_list, should_write=self._options.run)
++
++ if self._options.run:
++ _log.info('Formatting updated %d files ...', len(self._updated_files))
++ git = Git(cwd=self._repo_root)
++ # |git cl format| can't handle too many files at once.
++ while len(self._updated_files) > 0:
++ end_index = 100
++ if end_index > len(self._updated_files):
++ end_index = len(self._updated_files)
++ git.run(['cl', 'format'] + self._updated_files[:end_index])
++ self._updated_files = self._updated_files[end_index:]
++
++ if not apply_only:
++ _log.info('Make a local commit ...')
++ git.commit_locally_with_message("""The Great Blink mv for source files, part 1.
++
++Update file contents without moving files.
++
++NOAUTOREVERT=true
++Bug: 768828
++""")
++
++ def move(self, apply_only=None):
++ """Move Blink source files.
++
++ Args:
++ apply_only: If it's None, move all affected files. Otherwise,
++ it should be a set of file paths and this function moves
++ only the files in |apply_only|.
++ """
++ _log.info('Planning renaming ...')
++ file_pairs = plan_blink_move(self._fs, [])
++
++ if apply_only:
++ file_pairs = [(src, dest) for (src, dest) in file_pairs
++ if 'third_party/WebKit/' + src.replace('\\', '/') in apply_only]
++ print 'Update file_pairs = ', file_pairs
++ _log.info('Will move %d files', len(file_pairs))
++
++ git = Git(cwd=self._repo_root)
++ files_set = self._get_checked_in_files(git)
++ for i, (src, dest) in enumerate(file_pairs):
++ src_from_repo = self._fs.join('third_party', 'WebKit', src)
++ if src_from_repo.replace('\\', '/') not in files_set:
++ _log.info('%s is not in the repository', src)
++ continue
++ dest_from_repo = self._fs.join('third_party', 'blink', dest)
++ self._fs.maybe_make_directory(self._repo_root, 'third_party', 'blink', self._fs.dirname(dest))
++ if self._options.run_git:
++ git.move(src_from_repo, dest_from_repo)
++ _log.info('[%d/%d] Git moved %s', i + 1, len(file_pairs), src)
++ else:
++ self._fs.move(self._fs.join(self._repo_root, src_from_repo),
++ self._fs.join(self._repo_root, dest_from_repo))
++ _log.info('[%d/%d] Moved %s', i + 1, len(file_pairs), src)
++ if apply_only:
++ return
++
++ self._update_single_file_content(
++ 'build/get_landmines.py',
++ [('\ndef main', ' print \'The Great Blink mv for source files (crbug.com/768828)\'\n\ndef main')])
++
++ _log.info('Run run-bindings-tests ...')
++ Executive().run_command(['python',
++ self._fs.join(get_scripts_dir(), 'run-bindings-tests'),
++ '--reset-results'],
++ cwd=self._repo_root)
++
++ if self._options.run_git:
++ _log.info('Make a local commit ...')
++ git.commit_locally_with_message("""The Great Blink mv for source files, part 2.
++
++Move and rename files.
++
++NOAUTOREVERT=true
++Bug: 768828
++""")
++
++ def fix_branch(self):
++ git = Git(cwd=self._repo_root)
++ status = self._get_local_change_status(git)
++ if len(status) == 0:
++ _log.info('No local changes.')
++ return
++ modified_files = {f for (s, f) in status if s != 'D'}
++ deleted_files = {f for (s, f) in status if s == 'D'}
++
++ self.update(apply_only=modified_files)
++ self.move(apply_only=modified_files)
++ try:
++ git.commit_locally_with_message('This commit should be squashed.')
++ except ScriptError:
++ _log.info('move_blink_source.py modified nothing.')
++
++ # TODO(tkent): Show a message about deleted_files.
++
++ def _get_local_change_status(self, git):
++ """Returns a list of tuples representing local change summary.
++
++ Each tuple contains two strings. The first one is file change status
++ such as "M", "D". See --diff-filter section of git-diff manual page.
++ The second one is file name relative to the repository top.
++ """
++
++ base_commit = git.run(['show-branch', '--merge-base', 'master', 'HEAD']).strip()
++ # Note that file names in the following command result are always
++ # slash-separated, even on Windows.
++ status_lines = git.run(['diff', '--name-status', '--no-renames', base_commit]).split('\n')
++ status_tuple_list = []
++ for l in status_lines:
++ items = l.split('\t')
++ if len(items) == 2:
++ status_tuple_list.append(tuple(items))
++ elif len(l) > 0:
++ _log.warning('Unrecognized diff output: "%s"', l)
++ return status_tuple_list
++
++ def _get_checked_in_files(self, git):
++ files_text = git.run(['ls-files',
++ 'third_party/WebKit/Source',
++ 'third_party/WebKit/common',
++ 'third_party/WebKit/public'])
++ return set(files_text.split('\n'))
++
++ def _create_basename_maps(self, file_pairs):
++ basename_map = {}
++ # Generated inspector/protocol/* contains a lot of names duplicated with
++ # checked-in core files. We don't want to rename them, and don't want to
++ # replace them in BUILD.gn and #include accidentally.
++ pattern = r'(?<!inspector/protocol/)\b('
++ idl_headers = set()
++ header_pattern = r'(?<!inspector/protocol/)\b('
++ for source, dest in file_pairs:
++ _, source_base = self._fs.split(source)
++ _, dest_base = self._fs.split(dest)
++ # OriginTrialFeaturesForCore.h in bindings/tests/results/modules/
++ # confuses generated/checked-in detection in _replace_include_path().
++ if 'bindings/tests' in source.replace('\\', '/'):
++ continue
++ if source_base.endswith('.h'):
++ header_pattern += re.escape(source_base) + '|'
++ if source_base == dest_base:
++ continue
++ basename_map[source_base] = dest_base
++ pattern += re.escape(source_base) + '|'
++ # IDL sometimes generates implementation files as well as
++ # binding files. We'd like to update #includes for such files.
++ if source_base.endswith('.idl'):
++ source_header = source_base.replace('.idl', '.h')
++ basename_map[source_header] = dest_base.replace('.idl', '.h')
++ pattern += re.escape(source_header) + '|'
++ idl_headers.add(source_header)
++ _log.info('Rename %d files for snake_case', len(basename_map))
++ self._basename_map = basename_map
++ self._basename_re = re.compile(pattern[0:len(pattern) - 1] + ')(?=["\']|$)')
++ self._idl_generated_impl_headers = idl_headers
++ self._checked_in_header_re = re.compile(header_pattern[0:len(header_pattern) - 1] + ')$')
++
++ def _shorten_path(self, path):
++ if path.startswith(self._repo_root):
++ return path[len(self._repo_root) + 1:]
++ return path
++
++ @staticmethod
++ def _filter_file(fs, dirname, basename):
++ return FileType.detect(fs.join(dirname, basename)) != FileType.NONE
++
++ def _update_build(self, content):
++ content = content.replace('//third_party/WebKit/Source', '//third_party/blink/renderer')
++ content = content.replace('//third_party/WebKit/common', '//third_party/blink/common')
++ content = content.replace('//third_party/WebKit/public', '//third_party/blink/renderer/public')
++ # export_header_blink exists outside of Blink too.
++ content = content.replace('export_header_blink = "third_party/WebKit/public/platform/WebCommon.h"',
++ 'export_header_blink = "third_party/blink/renderer/public/platform/web_common.h"')
++ return content
++
++ def _update_blink_build(self, content):
++ content = self._update_build(content)
++
++ # Update visibility=[...]
++ content = content.replace('//third_party/WebKit/*', '//third_party/blink/*')
++ content = content.replace('//third_party/WebKit/Source/*', '//third_party/blink/renderer/*')
++ content = content.replace('//third_party/WebKit/public/*', '//third_party/blink/renderer/public/*')
++
++ # Update mojom variables
++ content = content.replace('export_header = "third_party/WebKit/common',
++ 'export_header = "third_party/blink/common')
++ content = content.replace('export_header_blink = "third_party/WebKit/Source',
++ 'export_header_blink = "third_party/blink/renderer')
++ return self._update_basename(content)
++
++ def _update_owners(self, content):
++ content = content.replace('//third_party/WebKit/Source', '//third_party/blink/renderer')
++ content = content.replace('//third_party/WebKit/common', '//third_party/blink/common')
++ content = content.replace('//third_party/WebKit/public', '//third_party/blink/renderer/public')
++ return content
++
++ def _update_deps(self, content):
++ original_content = content
++ content = content.replace('third_party/WebKit/Source', 'third_party/blink/renderer')
++ content = content.replace('third_party/WebKit/common', 'third_party/blink/common')
++ content = content.replace('third_party/WebKit/public', 'third_party/blink/renderer/public')
++ content = content.replace('third_party/WebKit', 'third_party/blink')
++ if original_content == content:
++ return content
++ return self._update_basename(content)
++
++ def _update_mojom(self, content):
++ content = content.replace('third_party/WebKit/public', 'third_party/blink/renderer/public')
++ content = content.replace('third_party/WebKit/common', 'third_party/blink/common')
++ return content
++
++ def _update_typemap(self, content):
++ content = content.replace('//third_party/WebKit/Source', '//third_party/blink/renderer')
++ content = content.replace('//third_party/WebKit/common', '//third_party/blink/common')
++ content = content.replace('//third_party/WebKit/public', '//third_party/blink/renderer/public')
++ return self._update_basename(content)
++
++ def _update_blink_build_py(self, content):
++ # We don't prepend 'third_party/blink/renderer/' to matched basenames
++ # because it won't affect build and manual update after the great mv is
++ # enough.
++ return self._update_basename(content)
++
++ def _update_layout_tests(self, content):
++ return content.replace('file:///gen/third_party/WebKit/', 'file:///gen/third_party/blink/renderer/')
++
++ def _update_basename(self, content):
++ return self._basename_re.sub(lambda match: self._basename_map[match.group(1)], content)
++
++ @staticmethod
++ def _append_unless_upper_dir_exists(dirs, new_dir):
++ for i in range(0, len(dirs)):
++ if new_dir.startswith(dirs[i]):
++ return
++ if dirs[i].startswith(new_dir):
++ dirs[i] = new_dir
++ return
++ dirs.append(new_dir)
++
++ def _update_file_content(self, apply_only):
++ _log.info('Find *.gn, *.mojom, *.py, *.typemap, DEPS, and OWNERS ...')
++ files = self._fs.files_under(
++ self._repo_root, dirs_to_skip=['.git', 'out'], file_filter=self._filter_file)
++ _log.info('Scan contents of %d files ...', len(files))
++ updated_deps_dirs = []
++ for file_path in files:
++ file_type = FileType.detect(file_path)
++ original_content = self._fs.read_text_file(file_path)
++ content = original_content
++ if file_type == FileType.BUILD:
++ content = self._update_build(content)
++ elif file_type == FileType.BLINK_BUILD:
++ content = self._update_blink_build(content)
++ elif file_type == FileType.OWNERS:
++ content = self._update_owners(content)
++ elif file_type == FileType.DEPS:
++ if self._fs.dirname(file_path) == self._repo_root:
++ _log.info("Skip //DEPS")
++ continue
++ content = self._update_deps(content)
++ elif file_type == FileType.MOJOM:
++ content = self._update_mojom(content)
++ elif file_type == FileType.TYPEMAP:
++ content = self._update_typemap(content)
++ elif file_type == FileType.BLINK_BUILD_PY:
++ content = self._update_blink_build_py(content)
++ elif file_type == FileType.LAYOUT_TESTS_WITH_MOJOM:
++ content = self._update_layout_tests(content)
++
++ if original_content == content:
++ continue
++ if self._options.run and (not apply_only or file_path.replace('\\', '/') in apply_only):
++ self._fs.write_text_file(file_path, content)
++ self._updated_files.append(file_path)
++ if file_type == FileType.DEPS:
++ self._append_unless_upper_dir_exists(updated_deps_dirs, self._fs.dirname(file_path))
++ _log.info('Updated %s', self._shorten_path(file_path))
++ return updated_deps_dirs
++
++ def _update_cpp_includes_in_directories(self, dirs, apply_only):
++ for dirname in dirs:
++ _log.info('Processing #include in %s ...', self._shorten_path(dirname))
++ files = self._fs.files_under(
++ dirname, file_filter=lambda fs, _, basename: basename.endswith(
++ ('.h', '.cc', '.cpp', '.mm', '.cc.tmpl', '.cpp.tmpl',
++ '.h.tmpl', 'XPathGrammar.y', '.gperf')))
++ for file_path in files:
++ posix_file_path = file_path.replace('\\', '/')
++ original_content = self._fs.read_text_file(file_path)
++
++ content = self._update_cpp_includes(original_content)
++ if file_path.endswith('.h') and '/third_party/WebKit/public/' in posix_file_path:
++ content = self._update_basename_only_includes(content, file_path)
++ if file_path.endswith('.h') and '/third_party/WebKit/' in posix_file_path:
++ content = self._update_include_guard(content, file_path)
++
++ if original_content == content:
++ continue
++ if self._options.run and (not apply_only or posix_file_path in apply_only):
++ self._fs.write_text_file(file_path, content)
++ self._updated_files.append(file_path)
++ _log.info('Updated %s', self._shorten_path(file_path))
++
++ def _replace_include_path(self, match):
++ include_or_import = match.group(1)
++ path = match.group(2)
++
++ # If |path| starts with 'third_party/WebKit', we should adjust the
++ # directory name for third_party/blink, and replace its basename by
++ # self._basename_map.
++ #
++ # If |path| starts with a Blink-internal directory such as bindings,
++ # core, modules, platform, public, it refers to a checked-in file, or a
++ # generated file. For the former, we should add
++ # 'third_party/blink/renderer/' and replace the basename. For the
++ # latter, we should update the basename for a name mapped from an IDL
++ # renaming, and should not add 'third_party/blink/renderer'.
++
++ if path.startswith('third_party/WebKit'):
++ path = path.replace('third_party/WebKit/Source', 'third_party/blink/renderer')
++ path = path.replace('third_party/WebKit/common', 'third_party/blink/common')
++ path = path.replace('third_party/WebKit/public', 'third_party/blink/renderer/public')
++ path = self._update_basename(path)
++ return '#%s "%s"' % (include_or_import, path)
++
++ match = self._checked_in_header_re.search(path)
++ if match:
++ if match.group(1) in self._basename_map:
++ path = 'third_party/blink/renderer/' + path[:match.start(1)] + self._basename_map[match.group(1)]
++ else:
++ path = 'third_party/blink/renderer/' + path
++ elif 'core/inspector/protocol/' not in path:
++ basename_start = path.rfind('/') + 1
++ basename = path[basename_start:]
++ if basename in self._idl_generated_impl_headers:
++ path = path[:basename_start] + self._basename_map[basename]
++ elif basename.startswith('V8'):
++ path = path[:basename_start] + NameStyleConverter(basename[:len(basename) - 2]).to_snake_case() + '.h'
++ return '#%s "%s"' % (include_or_import, path)
++
++ def _update_cpp_includes(self, content):
++ pattern = re.compile(r'#(include|import)\s+"((bindings|core|modules|platform|public|' +
++ r'third_party/WebKit/(Source|common|public))/[-_\w/.]+)"')
++ return pattern.sub(self._replace_include_path, content)
++
++ def _replace_basename_only_include(self, subdir, source_path, match):
++ source_basename = match.group(1)
++ if source_basename in self._basename_map:
++ return '#include "third_party/blink/renderer/public/%s/%s"' % (subdir, self._basename_map[source_basename])
++ _log.warning('Basename-only %s in %s', match.group(0), self._shorten_path(source_path))
++ return match.group(0)
++
++ def _update_basename_only_includes(self, content, source_path):
++ if not source_path.endswith('.h') or '/third_party/WebKit/public/' not in source_path.replace('\\', '/'):
++ return
++ # In public/ header files, we should replace |#include "WebFoo.h"|
++ # with |#include "third_party/blink/renderer/public/platform-or-web/web_foo.h"|
++ subdir = self._fs.basename(self._fs.dirname(source_path))
++ # subdir is 'web' or 'platform'.
++ return re.sub(r'#include\s+"(\w+\.h)"',
++ partial(self._replace_basename_only_include, subdir, source_path), content)
++
++ def _update_include_guard(self, content, source_path):
++ current_guard = re.sub(r'[.]', '_', self._fs.basename(source_path))
++ new_path = relative_dest(self._fs, self._fs.relpath(
++ source_path, start=self._fs.join(self._repo_root, 'third_party', 'WebKit')))
++ new_guard = 'THIRD_PARTY_BLINK_' + re.sub(r'[\\/.]', '_', new_path.upper()) + '_'
++ content = re.sub(r'#ifndef\s+(WTF_)?' + current_guard, '#ifndef ' + new_guard, content);
++ content = re.sub(r'#define\s+(WTF_)?' + current_guard, '#define ' + new_guard, content);
++ content = re.sub(r'#endif\s+//\s+(WTF_)?' + current_guard, '#endif // ' + new_guard, content);
++ return content
++
++ def _update_single_file_content(self, file_path, replace_list, should_write=True):
++ full_path = self._fs.join(self._repo_root, file_path)
++ original_content = self._fs.read_text_file(full_path)
++ content = original_content
++ for command in replace_list:
++ if isinstance(command, tuple):
++ src, dest = command
++ content = content.replace(src, dest)
++ elif callable(command):
++ content = command(content)
++ else:
++ raise TypeError('A tuple or a function is expected.')
++ if content != original_content:
++ if should_write:
++ self._fs.write_text_file(full_path, content)
++ self._updated_files.append(full_path)
++ _log.info('Updated %s', file_path)
++ else:
++ _log.warning('%s does not contain specified source strings.', file_path)
++
++
++def main():
++ logging.basicConfig(level=logging.DEBUG,
++ format='[%(asctime)s %(levelname)s %(name)s] %(message)s',
++ datefmt='%H:%M:%S')
++ parser = argparse.ArgumentParser(description='Blink source mover')
++ sub_parsers = parser.add_subparsers()
++
++ update_parser = sub_parsers.add_parser('update')
++ update_parser.set_defaults(command='update')
++ update_parser.add_argument('--run', dest='run', action='store_true',
++ help='Update file contents')
++
++ move_parser = sub_parsers.add_parser('move')
++ move_parser.set_defaults(command='move')
++ move_parser.add_argument('--git', dest='run_git', action='store_true',
++ help='Run |git mv| command instead of |mv|.')
++
++ fixbranch_parser = sub_parsers.add_parser('fixbranch')
++ fixbranch_parser.set_defaults(command='fixbranch', run=True, run_git=True)
++
++ options = parser.parse_args()
++ mover = MoveBlinkSource(FileSystem(), options, get_chromium_src_dir())
++ if options.command == 'update':
++ mover.update()
++ elif options.command == 'move':
++ mover.move()
++ elif options.command == 'fixbranch':
++ mover.fix_branch()
++
++
++if __name__ == '__main__':
++ main()
+--- /dev/null
++++ b/third_party/blink/tools/plan_blink_move.py
+@@ -0,0 +1,96 @@
++#!/usr/bin/env vpython
++# Copyright 2017 The Chromium Authors. All rights reserved.
++# Use of this source code is governed by a BSD-style license that can be
++# found in the LICENSE file.
++
++import os
++import re
++import sys
++
++sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..',
++ 'third_party', 'WebKit', 'Tools', 'Scripts'))
++from blinkpy.common.name_style_converter import NameStyleConverter
++from webkitpy.common.system.filesystem import FileSystem
++
++
++def relative_dest(fs, filename):
++ """Returns a destination path string for given filename.
++
++ |filename| is a path relative to third_party/WebKit, and the resultant path
++ is relative to third_party/blink.
++ """
++ dest = None
++ if filename.startswith('public'):
++ dest = re.sub(r'^public', 'renderer' + fs.sep + 'public', filename)
++ elif filename.startswith('Source'):
++ dest = re.sub(r'^Source', 'renderer', filename)
++ elif filename.startswith('common'):
++ dest = filename
++ else:
++ raise ValueError('|filename| must start with "common", "public", or "Source": %s' % filename)
++ if filename.endswith(('.h', '.cpp', '.mm', '.idl', '.typemap', 'Settings.json5')):
++ dirname, basename = fs.split(dest)
++ basename, ext = fs.splitext(basename)
++ # Skip some inspector-related files. #includes for these files are
++ # generated by a script outside of Blink.
++ if (re.match(r'Inspector.*Agent', basename)
++ or basename == 'InspectorTraceEvents'
++ or basename == 'PerformanceMonitor'
++ or basename == 'PlatformTraceEventsAgent'):
++ return dest
++ # Skip CSSProperty*. Some files are generated, and some files are
++ # checked-in. It's hard to handle them automatically.
++ if re.search(r'css[\\/]properties$', dirname):
++ return dest
++ if filename.endswith('.cpp'):
++ ext = '.cc'
++ # WebKit.h should be renamed to blink.h.
++ if basename == 'WebKit' and ext == '.h':
++ basename = 'blink'
++ if basename.lower() != basename:
++ basename = NameStyleConverter(basename).to_snake_case()
++ return fs.join(dirname, basename + ext)
++ return dest
++
++
++def start_with_list(name, prefixes):
++ if len(prefixes) == 0:
++ return True
++ for prefix in prefixes:
++ if name.startswith(prefix):
++ return True
++ return False
++
++
++def plan_blink_move(fs, prefixes):
++ """Returns (source, dest) path pairs.
++
++ The source paths are relative to third_party/WebKit,
++ and the dest paths are relative to third_party/blink.
++ The paths use os.sep as the path part separator.
++ """
++ blink_dir = fs.join(fs.dirname(__file__), '..')
++ webkit_dir = fs.join(blink_dir, '..', '..', 'third_party', 'WebKit')
++ source_files = fs.files_under(fs.join(webkit_dir, 'Source'))
++ source_files += fs.files_under(fs.join(webkit_dir, 'common'))
++ source_files += fs.files_under(fs.join(webkit_dir, 'public'))
++
++ # It's possible to check git.exists() here, but we don't do it due to slow
++ # performance. We should check it just before executing git command.
++
++ source_files = [f[len(webkit_dir) + 1:] for f in source_files]
++ return [(f, relative_dest(fs, f)) for f in source_files
++ if f.find('node_modules') == -1 and start_with_list(f, prefixes)]
++
++
++def main():
++ fs = FileSystem()
++ file_pairs = plan_blink_move(fs, sys.argv[1:])
++ print 'Show renaming plan. It contains files not in the repository.'
++ print '<Source path relative to third_party/WebKit> => <Destination path relative to third_party/blink>'
++ for pair in file_pairs:
++ print '%s\t=>\t%s' % pair
++
++
++if __name__ == '__main__':
++ main()