Skip to content

Commit

Permalink
YouCompleteMe: better out(_android|_linux)? dir detection
Browse files Browse the repository at this point in the history
ninja_output.py currently relies solely on the GYP_GENERATOR_FLAGS
environment variable to detect custom out directories, but this
variable is rarely set when this script is invoked from YouCompleteMe.

For completeness, support is added for the CHROMIUM_OUT_DIR environment variable (it overrides GYP_GENERATOR_FLAGS).

But the main purpose of the patch is to handle the case where neither environment variable is set, and in this case automatically choose between out, out_android and out_linux (or any other out_* directories), by returning the most recently used one.

To calculate which is most recently used, instead of only looking at the modification time of 'build.ninja' and 'protoc' (neither of which seem to be updated during an incremental build), the maximum mtime amongst each directory and its top-level files is used, which should be more reliable.

Review URL: https://codereview.chromium.org/863593002

Cr-Commit-Position: refs/heads/master@{#312838}
  • Loading branch information
johnmellor authored and Commit bot committed Jan 23, 2015
1 parent 70adb31 commit 5ff5181
Showing 1 changed file with 44 additions and 31 deletions.
75 changes: 44 additions & 31 deletions tools/vim/ninja_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,53 @@

import os
import os.path
import re


def GetNinjaOutputDirectory(chrome_root, configuration=None):
"""Returns <chrome_root>/<output_dir>/(Release|Debug).
The output_dir is detected in the following ways, in order of precedence:
1. CHROMIUM_OUT_DIR environment variable.
2. GYP_GENERATOR_FLAGS environment variable output_dir property.
3. Symlink target, if src/out is a symlink.
4. Most recently modified (e.g. built) directory called out or out_*.
The configuration chosen is the one most recently generated/built, but can be
overriden via the <configuration> parameter. Detects a custom output_dir
specified by GYP_GENERATOR_FLAGS."""

output_dir = 'out'
generator_flags = os.getenv('GYP_GENERATOR_FLAGS', '').split(' ')
for flag in generator_flags:
name_value = flag.split('=', 1)
if len(name_value) == 2 and name_value[0] == 'output_dir':
output_dir = name_value[1]

root = os.path.join(chrome_root, output_dir)
if configuration:
return os.path.join(root, configuration)

debug_path = os.path.join(root, 'Debug')
release_path = os.path.join(root, 'Release')

def is_release_15s_newer(test_path):
try:
debug_mtime = os.path.getmtime(os.path.join(debug_path, test_path))
except os.error:
debug_mtime = 0
try:
rel_mtime = os.path.getmtime(os.path.join(release_path, test_path))
except os.error:
rel_mtime = 0
return rel_mtime - debug_mtime >= 15

if is_release_15s_newer('build.ninja') or is_release_15s_newer('protoc'):
return release_path
return debug_path
overriden via the <configuration> parameter."""

output_dirs = []
if ('CHROMIUM_OUT_DIR' in os.environ and
os.path.isdir(os.path.join(chrome_root, os.environ['CHROMIUM_OUT_DIR']))):
output_dirs = [os.environ['CHROMIUM_OUT_DIR']]
if not output_dirs:
generator_flags = os.getenv('GYP_GENERATOR_FLAGS', '').split(' ')
for flag in generator_flags:
name_value = flag.split('=', 1)
if (len(name_value) == 2 and name_value[0] == 'output_dir' and
os.path.isdir(os.path.join(chrome_root, name_value[1]))):
output_dirs = [name_value[1]]
if not output_dirs:
out = os.path.join(chrome_root, 'out')
if os.path.islink(out):
out_target = os.path.join(os.path.dirname(out), os.readlink(out))
if os.path.exists(out_target):
output_dirs = [out_target]
if not output_dirs:
for f in os.listdir(chrome_root):
if (re.match('out(?:$|_)', f) and
os.path.isdir(os.path.join(chrome_root, f))):
output_dirs.append(f)

configs = [configuration] if configuration else ['Debug', 'Release']
output_paths = [os.path.join(chrome_root, out_dir, config)
for out_dir in output_dirs for config in configs]

def approx_directory_mtime(path):
if not os.path.exists(path):
return -1
# This is a heuristic; don't recurse into subdirectories.
paths = [path] + [os.path.join(path, f) for f in os.listdir(path)]
return max(os.path.getmtime(p) for p in paths)

return max(output_paths, key=approx_directory_mtime)

0 comments on commit 5ff5181

Please sign in to comment.