blob: fffa53398d54604a8a9d54db874bc450e645b68f [file] [log] [blame]
#!/usr/bin/env python
#
# Copyright 2014 The Chromium OS 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 argparse
import itertools
import logging
import os
import re
import sys
import factory_common # pylint: disable=unused-import
from cros.factory.utils import cros_board_utils
from cros.factory.utils.process_utils import CheckOutput
from cros.factory.utils.process_utils import Spawn
RE_PACKAGE_FILES = re.compile(r'.*?files/')
def GetFileToLint(path=None):
output = CheckOutput(
['git', 'status', '--untracked-files=all', '--porcelain'], cwd=path,
log=True)
# Remove first three characters, and anything up to the -> for renames.
uncommitted = [re.sub(r'^...(.+ -> )?', '', x) for x in output.splitlines()]
# The output contains full path as
# chromeos-base/{chromeos-,}factory-board/files/py/device/boards/test.py
# and we want to strip until 'files/'.
uncommitted = [re.sub(RE_PACKAGE_FILES, '', x) if path else x
for x in uncommitted if x.endswith('.py') and '#' not in x]
logging.info('Uncommitted files: %r', uncommitted)
all_files = set(uncommitted)
for i in itertools.count():
commit = 'HEAD~%d' % i
proc = Spawn(['git', 'log', '-1', commit], cwd=path, read_stdout=True)
if proc.returncode:
# No more log entries
break
if '\n Reviewed-on: ' in proc.stdout_data:
logging.info('%s has Reviewed-on; ending search', commit)
break
files = CheckOutput(['git', 'diff-tree', '--no-commit-id', '--name-only',
'-r', commit], cwd=path, log=True).splitlines()
logging.info('%s contains files %s', commit, files)
for f in files:
file_path = os.path.join(path, f) if path else f
if f.endswith('.py') and os.path.exists(file_path):
all_files.add(re.sub(RE_PACKAGE_FILES, '', f) if path else f)
all_files = set(f for f in all_files if os.path.exists(f))
return all_files
def main():
parser = argparse.ArgumentParser(
description='Lints files that are new, changed, or in a pending CL.')
parser.add_argument('--verbose', '-v', action='count')
parser.add_argument('--overlay', '-o')
args = parser.parse_args()
logging.basicConfig(level=logging.WARNING - 10 * (args.verbose or 0))
# chdir to repo root so paths are all correct
os.chdir(CheckOutput(['git', 'rev-parse', '--show-toplevel']).strip())
all_files = GetFileToLint()
if args.overlay:
overlay_path = cros_board_utils.GetChromeOSFactoryBoardPath(args.overlay)
if overlay_path:
all_files |= GetFileToLint(os.path.join(overlay_path, '../..'))
CheckOutput(['make', 'overlay-%s' % args.overlay])
all_files_str = ' '.join(sorted(all_files))
overlay_args = ['-C', 'overlay-%s' % args.overlay] if args.overlay else []
proc = Spawn(
['make'] + overlay_args + ['lint', 'LINT_FILES=%s' % all_files_str],
call=True, log=True)
sys.exit(proc.returncode)
if __name__ == '__main__':
main()