[go: up one dir, main page]

blob: 323711ff32e23f984f41ff7af505ec8e5d4acb64 [file] [log] [blame]
Brian Ryner3ff8bea2024-01-02 00:32:131#!/usr/bin/env vpython3
iannucci20f41802015-06-10 00:01:562# Copyright 2014 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Quinten Yearsley110d6122019-05-28 22:10:496"""Python wrapper for various Go tools.
7
8Intended to be used from a PRESUBMIT check.
9"""
iannucci20f41802015-06-10 00:01:5610
11import os
12import subprocess
13import sys
14
iannucci20f41802015-06-10 00:01:5615WORKSPACE_ROOT = os.path.dirname(os.path.abspath(__file__))
16
iannucci20f41802015-06-10 00:01:5617
Takuto Ikuta875c2742019-02-28 16:38:5018def group_by_dir(filestream):
Quinten Yearsley110d6122019-05-28 22:10:4919 """Generates directories of the files in the given filestream.
20
21 If the filestream has paths in sorted order, then directories
22 shouldn't be repeated.
Vadim Shtayura5c22e8e2021-07-13 21:19:5923
24 Skips files that reside in a "testdata" directory.
Quinten Yearsley110d6122019-05-28 22:10:4925 """
iannucci20f41802015-06-10 00:01:5626 prefix = None
27 group = []
28 for fname in filestream:
29 dirname = os.path.dirname(fname)
Vadim Shtayura5c22e8e2021-07-13 21:19:5930 if '/testdata/' in os.path.normpath(dirname):
31 continue
iannucci20f41802015-06-10 00:01:5632 if dirname != prefix:
33 if group:
Quinten Yearsley110d6122019-05-28 22:10:4934 yield prefix
iannucci20f41802015-06-10 00:01:5635 prefix = dirname
36 group = []
37 group.append(fname)
38 if group:
Quinten Yearsley110d6122019-05-28 22:10:4939 yield prefix
iannucci20f41802015-06-10 00:01:5640
41
Takuto Ikuta875c2742019-02-28 16:38:5042def mk_checker(*tool_name):
Quinten Yearsley110d6122019-05-28 22:10:4943 """Creates and returns a "main" function.
44
45 The returned function invokes the tool and returns the retcode-style result.
46 """
47 tool_cmd = list(tool_name)
iannucci20f41802015-06-10 00:01:5648
49 def _inner(_verbose, filestream):
Stephen Martinis2f071622016-08-19 18:00:1350 found_errs = []
51 retcode = 0
Robert Iannucci2c2344f2018-12-11 00:32:4152
Quinten Yearsley110d6122019-05-28 22:10:4953 for dpath in group_by_dir(filestream):
iannucci20f41802015-06-10 00:01:5654 proc = subprocess.Popen(
Vadim Shtayura33fc8062021-07-14 22:55:3955 tool_cmd + ['.'],
56 cwd=dpath,
iannucci20f41802015-06-10 00:01:5657 stdout=subprocess.PIPE,
Takuto Ikutaf0ac9012022-06-24 01:42:1158 stderr=subprocess.STDOUT,
59 universal_newlines=True)
iannucci20f41802015-06-10 00:01:5660 out = proc.communicate()[0].strip()
Vadim Shtayura33fc8062021-07-14 22:55:3961 if proc.returncode and 'build constraints exclude all Go files' in out:
62 continue
iannucci20f41802015-06-10 00:01:5663 if out or proc.returncode:
Stephen Martinis2f071622016-08-19 18:00:1364 found_errs.append(out or 'Unrecognized error')
65 retcode = proc.returncode or 1
66
67 for err in found_errs:
Takuto Ikuta54517f42021-03-10 06:04:4968 print(err)
Stephen Martinis2f071622016-08-19 18:00:1369 return retcode
iannucci20f41802015-06-10 00:01:5670 return _inner
71
72
73def gofmt_main(verbose, filestream):
Quinten Yearsley110d6122019-05-28 22:10:4974 """Reads list of paths from stdin.
75
76 Expects go toolset to be in PATH (use ./env.py to set this up).
77 """
iannucci20f41802015-06-10 00:01:5678 def check_file(path):
79 proc = subprocess.Popen(
vadimshcd7ed9f2015-10-08 19:13:4880 ['gofmt', '-s', '-d', path],
iannucci20f41802015-06-10 00:01:5681 stdout=subprocess.PIPE,
82 stderr=subprocess.PIPE)
83 out, err = proc.communicate()
84 if proc.returncode:
Takuto Ikuta54517f42021-03-10 06:04:4985 print(err, end=' ')
iannucci20f41802015-06-10 00:01:5686 return False
87 if out:
88 if verbose:
Takuto Ikuta54517f42021-03-10 06:04:4989 print(out, end=' ')
iannucci20f41802015-06-10 00:01:5690 return False
91 return True
92
93 bad = []
94 for fpath in filestream:
95 if not check_file(fpath):
96 bad.append(fpath)
97 if bad:
98 root = WORKSPACE_ROOT.rstrip(os.sep) + os.sep
Takuto Ikuta54517f42021-03-10 06:04:4999 print('Badly formated Go files:')
iannucci20f41802015-06-10 00:01:56100 for p in bad:
101 if p.startswith(root):
102 p = p[len(root):]
Takuto Ikuta54517f42021-03-10 06:04:49103 print(' %s' % p)
104 print()
105 print('Consider running \'gofmt -s -w /path/to/infra\'')
iannucci20f41802015-06-10 00:01:56106 return 0 if not bad else 1
107
108
109def show_help():
Takuto Ikuta54517f42021-03-10 06:04:49110 print('Usage: check.py [--verbose] <tool>')
111 print('List of file paths to operate is read from stdin.')
112 print('Available tools:')
iannucci20f41802015-06-10 00:01:56113 for x in TOOL_FUNC:
Takuto Ikuta54517f42021-03-10 06:04:49114 print(" *", x)
iannucci20f41802015-06-10 00:01:56115 sys.exit(1)
116
117
118def main(args):
119 if len(args) < 1 or args[0] not in TOOL_FUNC:
120 show_help()
121
iannucci20f41802015-06-10 00:01:56122 verbose = '--verbose' in args
123
124 def filestream():
125 for path in sys.stdin:
126 path = path.rstrip()
Vadim Shtayurafe4263b2018-11-12 21:17:31127 if path:
128 yield path
iannucci20f41802015-06-10 00:01:56129
130 return TOOL_FUNC[args[0]](verbose, filestream())
131
132
133TOOL_FUNC = {
Gregory Nisbet4a5aedc2022-05-10 03:24:19134 # TODO(gregorynisbet): tricium copies around proto messages.
135 # Disable copylock analysis for now.
136 "govet": mk_checker("go", "vet", "-copylocks=false"),
iannucci20f41802015-06-10 00:01:56137 "gofmt": gofmt_main,
138}
139
140
141if __name__ == '__main__':
142 sys.exit(main(sys.argv[1:]))