mirror of
https://chromium.googlesource.com/chromium/tools/depot_tools.git
synced 2026-01-11 18:51:29 +00:00
Depot tools: use the clang-format binaries that are now included
as part of the Chromium checkout. This follows the approach used by gn. Changes include: - in-the-PATH clang-format trampoline scripts - clang_format.py, which finds clang-format binaries inside of Chrome - Hook 'git cl format' to the new binaries and scripts - Rearrange some code, for reuse between clang_format.py and gn.py BUG=240309 TEST=presubmits (one failure on mac, but it fails on a clean checkout too) Review URL: https://codereview.chromium.org/134313007 git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@245074 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
8
clang-format
Executable file
8
clang-format
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2014 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.
|
||||
|
||||
base_dir=$(dirname "$0")
|
||||
|
||||
PYTHONDONTWRITEBYTECODE=1 exec python "$base_dir/clang_format.py" "$@"
|
||||
10
clang-format.bat
Normal file
10
clang-format.bat
Normal file
@@ -0,0 +1,10 @@
|
||||
@echo off
|
||||
:: Copyright 2014 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.
|
||||
|
||||
:: This is required with cygwin only.
|
||||
PATH=%~dp0;%PATH%
|
||||
|
||||
:: Defer control.
|
||||
%~dp0python "%~dp0\clang_format.py" %*
|
||||
90
clang_format.py
Executable file
90
clang_format.py
Executable file
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright 2014 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.
|
||||
|
||||
"""Redirects to the version of clang-format checked into the Chrome tree.
|
||||
|
||||
clang-format binaries are pulled down from Google Cloud Storage whenever you
|
||||
sync Chrome, to platform-specific locations. This script knows how to locate
|
||||
those tools, assuming the script is invoked from inside a Chromium checkout."""
|
||||
|
||||
import gclient_utils
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
class NotFoundError(Exception):
|
||||
"""A file could not be found."""
|
||||
def __init__(self, e):
|
||||
Exception.__init__(self,
|
||||
'Problem while looking for clang-format in Chromium source tree:\n'
|
||||
' %s' % e)
|
||||
|
||||
|
||||
def _FindChromiumTree():
|
||||
"""Return the root of the current chromium checkout, or die trying."""
|
||||
source_root = gclient_utils.FindFileUpwards('.gclient')
|
||||
if not source_root:
|
||||
raise NotFoundError(
|
||||
'.gclient file not found in any parent of the current path.')
|
||||
return source_root
|
||||
|
||||
|
||||
def FindClangFormatToolInChromiumTree():
|
||||
"""Return a path to the clang-format executable, or die trying."""
|
||||
# The binaries in platform-specific subdirectories in src/tools/gn/bin.
|
||||
tool_path = os.path.join(_FindChromiumTree(), 'src', 'third_party',
|
||||
'clang_format', 'bin',
|
||||
gclient_utils.GetMacWinOrLinux(),
|
||||
'clang-format' + gclient_utils.GetExeSuffix())
|
||||
if not os.path.exists(tool_path):
|
||||
# TODO(nick): After March 2014, eliminate the following advisory.
|
||||
error_text = '''\n GIT CL FORMAT - WINTER WEATHER ADVISORY
|
||||
|
||||
clang-format binaries now come with every Chrome checkout!
|
||||
|
||||
Unfortunately, your depot_tools scripts tried to find clang-format binaries
|
||||
in your Chrome checkout, but failed. This is expected if you haven't synced
|
||||
since the binaries were added.
|
||||
|
||||
'git cl format' will probably not work until you sync your Chrome tree.
|
||||
Sorry about that.
|
||||
|
||||
Contact nick@chromium.org if you have any additional questions.\n\n'''
|
||||
|
||||
error_text += 'File does not exist: %s' % tool_path
|
||||
|
||||
raise NotFoundError(error_text)
|
||||
return tool_path
|
||||
|
||||
|
||||
def FindClangFormatScriptInChromiumTree(script_name):
|
||||
"""Return a path to a clang-format helper script, or die trying."""
|
||||
# The binaries in platform-specific subdirectories in src/tools/gn/bin.
|
||||
script_path = os.path.join(_FindChromiumTree(), 'src', 'third_party',
|
||||
'clang_format', 'scripts', script_name)
|
||||
if not os.path.exists(script_path):
|
||||
raise NotFoundError('File does not exist: %s' % script_path)
|
||||
return script_path
|
||||
|
||||
|
||||
def main(args):
|
||||
try:
|
||||
tool = FindClangFormatToolInChromiumTree()
|
||||
except NotFoundError, e:
|
||||
print >> sys.stderr, e
|
||||
sys.exit(1)
|
||||
|
||||
# Add some visibility to --help showing where the tool lives, since this
|
||||
# redirection can be a little opaque.
|
||||
help_syntax = ('-h', '--help', '-help', '-help-list', '--help-list')
|
||||
if any(match in args for match in help_syntax):
|
||||
print '\nDepot tools redirects you to the clang-format at:\n %s\n' % tool
|
||||
|
||||
return subprocess.call([tool] + sys.argv[1:])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
||||
@@ -33,6 +33,7 @@ class Error(Exception):
|
||||
msg = '\n'.join('%d> %s' % (index, l) for l in msg.splitlines())
|
||||
super(Error, self).__init__(msg, *args, **kwargs)
|
||||
|
||||
|
||||
def SplitUrlRevision(url):
|
||||
"""Splits url and returns a two-tuple: url, rev"""
|
||||
if url.startswith('ssh:'):
|
||||
@@ -103,10 +104,10 @@ def FileWrite(filename, content, mode='w'):
|
||||
def safe_rename(old, new):
|
||||
"""Renames a file reliably.
|
||||
|
||||
Sometimes os.rename does not work because a dying git process keeps a handle
|
||||
on it for a few seconds. An exception is then thrown, which make the program
|
||||
Sometimes os.rename does not work because a dying git process keeps a handle
|
||||
on it for a few seconds. An exception is then thrown, which make the program
|
||||
give up what it was doing and remove what was deleted.
|
||||
The only solution is to catch the exception and try again until it works.
|
||||
The only solution is to catch the exception and try again until it works.
|
||||
"""
|
||||
# roughly 10s
|
||||
retries = 100
|
||||
@@ -560,6 +561,24 @@ def FindFileUpwards(filename, path=None):
|
||||
path = new_path
|
||||
|
||||
|
||||
def GetMacWinOrLinux():
|
||||
"""Returns 'mac', 'win', or 'linux', matching the current platform."""
|
||||
if sys.platform.startswith(('cygwin', 'win')):
|
||||
return 'win'
|
||||
elif sys.platform.startswith('linux'):
|
||||
return 'linux'
|
||||
elif sys.platform == 'darwin':
|
||||
return 'mac'
|
||||
raise Error('Unknown platform: ' + sys.platform)
|
||||
|
||||
|
||||
def GetExeSuffix():
|
||||
"""Returns '' or '.exe' depending on how executables work on this platform."""
|
||||
if sys.platform.startswith(('cygwin', 'win')):
|
||||
return '.exe'
|
||||
return ''
|
||||
|
||||
|
||||
def GetGClientRootAndEntries(path=None):
|
||||
"""Returns the gclient root and the dict of entries."""
|
||||
config_file = '.gclient_entries'
|
||||
|
||||
35
git_cl.py
35
git_cl.py
@@ -32,6 +32,7 @@ except ImportError:
|
||||
from third_party import colorama
|
||||
from third_party import upload
|
||||
import breakpad # pylint: disable=W0611
|
||||
import clang_format
|
||||
import fix_encoding
|
||||
import gclient_utils
|
||||
import presubmit_support
|
||||
@@ -269,7 +270,7 @@ class Settings(object):
|
||||
if not self.updated:
|
||||
# The only value that actually changes the behavior is
|
||||
# autoupdate = "false". Everything else means "true".
|
||||
autoupdate = RunGit(['config', 'rietveld.autoupdate'],
|
||||
autoupdate = RunGit(['config', 'rietveld.autoupdate'],
|
||||
error_ok=True
|
||||
).strip().lower()
|
||||
|
||||
@@ -2342,7 +2343,14 @@ def CMDformat(parser, args):
|
||||
diff_cmd += ['*' + ext for ext in CLANG_EXTS]
|
||||
diff_output = RunGit(diff_cmd)
|
||||
|
||||
top_dir = RunGit(["rev-parse", "--show-toplevel"]).rstrip('\n')
|
||||
top_dir = os.path.normpath(
|
||||
RunGit(["rev-parse", "--show-toplevel"]).rstrip('\n'))
|
||||
|
||||
# Locate the clang-format binary in the checkout
|
||||
try:
|
||||
clang_format_tool = clang_format.FindClangFormatToolInChromiumTree()
|
||||
except clang_format.NotFoundError, e:
|
||||
DieWithError(e)
|
||||
|
||||
if opts.full:
|
||||
# diff_output is a list of files to send to clang-format.
|
||||
@@ -2350,24 +2358,21 @@ def CMDformat(parser, args):
|
||||
if not files:
|
||||
print "Nothing to format."
|
||||
return 0
|
||||
RunCommand(['clang-format', '-i', '-style', 'Chromium'] + files,
|
||||
RunCommand([clang_format_tool, '-i', '-style', 'Chromium'] + files,
|
||||
cwd=top_dir)
|
||||
else:
|
||||
env = os.environ.copy()
|
||||
env['PATH'] = os.path.dirname(clang_format_tool)
|
||||
# diff_output is a patch to send to clang-format-diff.py
|
||||
cfd_path = os.path.join('/usr', 'lib', 'clang-format',
|
||||
'clang-format-diff.py')
|
||||
if not os.path.exists(cfd_path):
|
||||
DieWithError('Could not find clang-format-diff at %s.' % cfd_path)
|
||||
cmd = [sys.executable, cfd_path, '-p0', '-style', 'Chromium']
|
||||
try:
|
||||
script = clang_format.FindClangFormatScriptInChromiumTree(
|
||||
'clang-format-diff.py')
|
||||
except clang_format.NotFoundError, e:
|
||||
DieWithError(e)
|
||||
|
||||
# Newer versions of clang-format-diff.py require an explicit -i flag
|
||||
# to apply the edits to files, otherwise it just displays a diff.
|
||||
# Probe the usage string to verify if this is needed.
|
||||
help_text = RunCommand([sys.executable, cfd_path, '-h'])
|
||||
if '[-i]' in help_text:
|
||||
cmd.append('-i')
|
||||
cmd = [sys.executable, script, '-p0', '-style', 'Chromium', '-i']
|
||||
|
||||
RunCommand(cmd, stdin=diff_output, cwd=top_dir)
|
||||
RunCommand(cmd, stdin=diff_output, cwd=top_dir, env=env)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
40
gn.py
Normal file → Executable file
40
gn.py
Normal file → Executable file
@@ -12,55 +12,27 @@ binary. It will also automatically try to find the gn binary when run inside
|
||||
the chrome source tree, so users can just type "gn" on the command line
|
||||
(normally depot_tools is on the path)."""
|
||||
|
||||
import gclient_utils
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
class PlatformUnknownError(IOError):
|
||||
pass
|
||||
|
||||
|
||||
def HasDotfile(path):
|
||||
"""Returns True if the given path has a .gn file in it."""
|
||||
return os.path.exists(path + '/.gn')
|
||||
|
||||
|
||||
def FindSourceRootOnPath():
|
||||
"""Searches upward from the current directory for the root of the source
|
||||
tree and returns the found path. Returns None if no source root could
|
||||
be found."""
|
||||
cur = os.getcwd()
|
||||
while True:
|
||||
if HasDotfile(cur):
|
||||
return cur
|
||||
up_one = os.path.dirname(cur)
|
||||
if up_one == cur:
|
||||
return None # Reached the top of the directory tree
|
||||
cur = up_one
|
||||
|
||||
|
||||
def RunGN(sourceroot):
|
||||
# The binaries in platform-specific subdirectories in src/tools/gn/bin.
|
||||
gnpath = sourceroot + '/tools/gn/bin/'
|
||||
if sys.platform in ('cygwin', 'win32'):
|
||||
gnpath += 'win/gn.exe'
|
||||
elif sys.platform.startswith('linux'):
|
||||
gnpath += 'linux/gn'
|
||||
elif sys.platform == 'darwin':
|
||||
gnpath += 'mac/gn'
|
||||
else:
|
||||
raise PlatformUnknownError('Unknown platform for GN: ' + sys.platform)
|
||||
|
||||
gnpath = os.path.join(sourceroot,
|
||||
'tools', 'gn', 'bin', gclient_utils.GetMacWinOrLinux(),
|
||||
'gn' + gclient_utils.GetExeSuffix())
|
||||
return subprocess.call([gnpath] + sys.argv[1:])
|
||||
|
||||
|
||||
def main(args):
|
||||
sourceroot = FindSourceRootOnPath()
|
||||
sourceroot = gclient_utils.FindFileUpwards('.gn')
|
||||
if not sourceroot:
|
||||
print >> sys.stderr, '.gn file not found in any parent of the current path.'
|
||||
sys.exit(1)
|
||||
return RunGN(sourceroot)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
||||
|
||||
@@ -31,15 +31,17 @@ class GclientUtilsUnittest(GclientUtilBase):
|
||||
'Annotated', 'AutoFlush', 'CheckCallAndFilter', 'CommandToStr',
|
||||
'CheckCallAndFilterAndHeader', 'Error', 'ExecutionQueue', 'FileRead',
|
||||
'FileWrite', 'FindFileUpwards', 'FindGclientRoot',
|
||||
'GetGClientRootAndEntries', 'GetEditor', 'IsDateRevision',
|
||||
'MakeDateRevision', 'MakeFileAutoFlush', 'MakeFileAnnotated',
|
||||
'PathDifference', 'ParseCodereviewSettingsContent', 'NumLocalCpus',
|
||||
'PrintableObject', 'RETRY_INITIAL_SLEEP', 'RETRY_MAX', 'RunEditor',
|
||||
'GCLIENT_CHILDREN', 'GCLIENT_CHILDREN_LOCK', 'GClientChildren',
|
||||
'SplitUrlRevision', 'SyntaxErrorToError', 'UpgradeToHttps', 'Wrapper',
|
||||
'WorkItem', 'codecs', 'lockedmethod', 'logging', 'os', 'pipes', 'Queue',
|
||||
're', 'rmtree', 'safe_makedirs', 'safe_rename', 'stat', 'subprocess',
|
||||
'GetGClientRootAndEntries', 'GetEditor', 'GetExeSuffix',
|
||||
'GetMacWinOrLinux', 'IsDateRevision', 'MakeDateRevision',
|
||||
'MakeFileAutoFlush', 'MakeFileAnnotated', 'PathDifference',
|
||||
'ParseCodereviewSettingsContent', 'NumLocalCpus', 'PrintableObject',
|
||||
'RETRY_INITIAL_SLEEP', 'RETRY_MAX', 'RunEditor', 'GCLIENT_CHILDREN',
|
||||
'GCLIENT_CHILDREN_LOCK', 'GClientChildren', 'SplitUrlRevision',
|
||||
'SyntaxErrorToError', 'UpgradeToHttps', 'Wrapper', 'WorkItem',
|
||||
'codecs', 'lockedmethod', 'logging', 'os', 'pipes', 'Queue', 're',
|
||||
'rmtree', 'safe_makedirs', 'safe_rename', 'stat', 'subprocess',
|
||||
'subprocess2', 'sys', 'tempfile', 'threading', 'time', 'urlparse',
|
||||
|
||||
]
|
||||
# If this test fails, you should add the relevant test.
|
||||
self.compareMembers(gclient_utils, members)
|
||||
|
||||
Reference in New Issue
Block a user