xref: /aosp_15_r20/external/perfetto/ui/format-sources (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*6dbdd20aSAndroid Build Coastguard Worker# Copyright (C) 2024 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker#
4*6dbdd20aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker#
8*6dbdd20aSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker#
10*6dbdd20aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker# limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker
16*6dbdd20aSAndroid Build Coastguard Workerimport argparse
17*6dbdd20aSAndroid Build Coastguard Workerimport os
18*6dbdd20aSAndroid Build Coastguard Workerimport sys
19*6dbdd20aSAndroid Build Coastguard Workerimport subprocess
20*6dbdd20aSAndroid Build Coastguard Worker
21*6dbdd20aSAndroid Build Coastguard WorkerUI_DIR = os.path.abspath(os.path.dirname(__file__))
22*6dbdd20aSAndroid Build Coastguard WorkerROOT_DIR = os.path.dirname(UI_DIR)
23*6dbdd20aSAndroid Build Coastguard WorkerPRETTIER_PATH = os.path.join(ROOT_DIR, 'ui/node_modules/.bin/prettier')
24*6dbdd20aSAndroid Build Coastguard WorkerESLINT_PATH = os.path.join(ROOT_DIR, 'ui/node_modules/.bin/eslint')
25*6dbdd20aSAndroid Build Coastguard Worker
26*6dbdd20aSAndroid Build Coastguard Worker
27*6dbdd20aSAndroid Build Coastguard Workerdef main():
28*6dbdd20aSAndroid Build Coastguard Worker  parser = argparse.ArgumentParser()
29*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument('--check-only', action='store_true')
30*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument('--no-prettier', action='store_true')
31*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument('--no-eslint', action='store_true')
32*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument(
33*6dbdd20aSAndroid Build Coastguard Worker      '--all',
34*6dbdd20aSAndroid Build Coastguard Worker      action='store_true',
35*6dbdd20aSAndroid Build Coastguard Worker      help='Prettify all .ts sources, not just the changed ones')
36*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument('filelist', nargs='*')
37*6dbdd20aSAndroid Build Coastguard Worker  args = parser.parse_args()
38*6dbdd20aSAndroid Build Coastguard Worker
39*6dbdd20aSAndroid Build Coastguard Worker  # We want to execute all the commands relative to UI_DIR, because eslint looks
40*6dbdd20aSAndroid Build Coastguard Worker  # for eslintrc in cwd. However, the user might pass paths that are relative to
41*6dbdd20aSAndroid Build Coastguard Worker  # the current cwd, which might be != UI_DIR.
42*6dbdd20aSAndroid Build Coastguard Worker  # So before running chdir relativize all the passed paths to UI_DIR
43*6dbdd20aSAndroid Build Coastguard Worker  filelist = [
44*6dbdd20aSAndroid Build Coastguard Worker      os.path.relpath(os.path.abspath(x), UI_DIR) for x in args.filelist
45*6dbdd20aSAndroid Build Coastguard Worker  ]
46*6dbdd20aSAndroid Build Coastguard Worker  os.chdir(UI_DIR)
47*6dbdd20aSAndroid Build Coastguard Worker
48*6dbdd20aSAndroid Build Coastguard Worker  # Need to add 'node' to the search path.
49*6dbdd20aSAndroid Build Coastguard Worker  os.environ['PATH'] += os.pathsep + os.path.join(ROOT_DIR, 'tools')
50*6dbdd20aSAndroid Build Coastguard Worker
51*6dbdd20aSAndroid Build Coastguard Worker  if not os.path.exists(PRETTIER_PATH):
52*6dbdd20aSAndroid Build Coastguard Worker    print('Cannot find %s' % PRETTIER_PATH)
53*6dbdd20aSAndroid Build Coastguard Worker    print('Run tools/install-build-deps --ui')
54*6dbdd20aSAndroid Build Coastguard Worker    return 1
55*6dbdd20aSAndroid Build Coastguard Worker
56*6dbdd20aSAndroid Build Coastguard Worker  with open('.prettierignore', 'r') as f:
57*6dbdd20aSAndroid Build Coastguard Worker    ignorelist = set(f.read().strip().split('\n'))
58*6dbdd20aSAndroid Build Coastguard Worker
59*6dbdd20aSAndroid Build Coastguard Worker  all_files = set()
60*6dbdd20aSAndroid Build Coastguard Worker  for root, _dirs, files in os.walk('src'):
61*6dbdd20aSAndroid Build Coastguard Worker    if root in ignorelist:
62*6dbdd20aSAndroid Build Coastguard Worker      continue
63*6dbdd20aSAndroid Build Coastguard Worker    for file in files:
64*6dbdd20aSAndroid Build Coastguard Worker      file_path = os.path.join(root, file)
65*6dbdd20aSAndroid Build Coastguard Worker      if os.path.splitext(file)[1].lower() in ['.ts', '.js', '.scss']:
66*6dbdd20aSAndroid Build Coastguard Worker        all_files.add(file_path)
67*6dbdd20aSAndroid Build Coastguard Worker
68*6dbdd20aSAndroid Build Coastguard Worker  files_to_check = []
69*6dbdd20aSAndroid Build Coastguard Worker  git_cmd = []
70*6dbdd20aSAndroid Build Coastguard Worker  if args.all:
71*6dbdd20aSAndroid Build Coastguard Worker    files_to_check = list(all_files)
72*6dbdd20aSAndroid Build Coastguard Worker  elif filelist:
73*6dbdd20aSAndroid Build Coastguard Worker    files_to_check = filelist
74*6dbdd20aSAndroid Build Coastguard Worker  else:
75*6dbdd20aSAndroid Build Coastguard Worker    upstream_branch = get_upstream_branch()
76*6dbdd20aSAndroid Build Coastguard Worker    git_cmd = ['git', 'diff', '--name-only', upstream_branch]
77*6dbdd20aSAndroid Build Coastguard Worker    git_output = subprocess.check_output(git_cmd, text=True).strip()
78*6dbdd20aSAndroid Build Coastguard Worker    changed_files = set(git_output.split('\n') if git_output else [])
79*6dbdd20aSAndroid Build Coastguard Worker    changed_files = [os.path.relpath(x, 'ui') for x in changed_files]
80*6dbdd20aSAndroid Build Coastguard Worker    files_to_check = all_files.intersection(changed_files)
81*6dbdd20aSAndroid Build Coastguard Worker
82*6dbdd20aSAndroid Build Coastguard Worker  prettier_args = ['--log-level=warn']
83*6dbdd20aSAndroid Build Coastguard Worker  eslint_args = []
84*6dbdd20aSAndroid Build Coastguard Worker  if args.check_only:
85*6dbdd20aSAndroid Build Coastguard Worker    prettier_args += ['--check']
86*6dbdd20aSAndroid Build Coastguard Worker  else:
87*6dbdd20aSAndroid Build Coastguard Worker    eslint_args += ['--fix']
88*6dbdd20aSAndroid Build Coastguard Worker    prettier_args += ['--write']
89*6dbdd20aSAndroid Build Coastguard Worker
90*6dbdd20aSAndroid Build Coastguard Worker  if len(files_to_check) == 0:
91*6dbdd20aSAndroid Build Coastguard Worker    if not args.check_only:
92*6dbdd20aSAndroid Build Coastguard Worker      # Be quiet when invoked by git cl presubmit.
93*6dbdd20aSAndroid Build Coastguard Worker      print('No changed files detected by `%s`' % ' '.join(git_cmd))
94*6dbdd20aSAndroid Build Coastguard Worker      print('Pass --all to prettify all ts/js/scss files in the repo')
95*6dbdd20aSAndroid Build Coastguard Worker    return 0
96*6dbdd20aSAndroid Build Coastguard Worker
97*6dbdd20aSAndroid Build Coastguard Worker  # Run prettier first
98*6dbdd20aSAndroid Build Coastguard Worker  if not args.no_prettier:
99*6dbdd20aSAndroid Build Coastguard Worker    print('Running prettier on %d files' % len(files_to_check))
100*6dbdd20aSAndroid Build Coastguard Worker    call_or_die([PRETTIER_PATH] + prettier_args + list(files_to_check))
101*6dbdd20aSAndroid Build Coastguard Worker
102*6dbdd20aSAndroid Build Coastguard Worker  # Then run eslint (but not on .scss)
103*6dbdd20aSAndroid Build Coastguard Worker  if not args.no_eslint:
104*6dbdd20aSAndroid Build Coastguard Worker    ts_js_only = lambda f: f.endswith('.ts') or f.endswith('.js')
105*6dbdd20aSAndroid Build Coastguard Worker    files_to_check = list(filter(ts_js_only, files_to_check))
106*6dbdd20aSAndroid Build Coastguard Worker    if len(files_to_check) > 0:
107*6dbdd20aSAndroid Build Coastguard Worker      print('Running eslint on %d files' % len(files_to_check))
108*6dbdd20aSAndroid Build Coastguard Worker      call_or_die([ESLINT_PATH] + eslint_args + files_to_check)
109*6dbdd20aSAndroid Build Coastguard Worker
110*6dbdd20aSAndroid Build Coastguard Worker
111*6dbdd20aSAndroid Build Coastguard Worker# Like subprocess.check_call, but in case of errors dies without printing a
112*6dbdd20aSAndroid Build Coastguard Worker# useless stacktrace that just muddies the stdout.
113*6dbdd20aSAndroid Build Coastguard Workerdef call_or_die(cmd):
114*6dbdd20aSAndroid Build Coastguard Worker  try:
115*6dbdd20aSAndroid Build Coastguard Worker    subprocess.check_call(cmd)
116*6dbdd20aSAndroid Build Coastguard Worker  except subprocess.CalledProcessError as ex:
117*6dbdd20aSAndroid Build Coastguard Worker    print('`%s` returned %d' % (' '.join(cmd)[:128], ex.returncode))
118*6dbdd20aSAndroid Build Coastguard Worker    sys.exit(ex.returncode)
119*6dbdd20aSAndroid Build Coastguard Worker
120*6dbdd20aSAndroid Build Coastguard Worker
121*6dbdd20aSAndroid Build Coastguard Workerdef get_upstream_branch():
122*6dbdd20aSAndroid Build Coastguard Worker  try:
123*6dbdd20aSAndroid Build Coastguard Worker    cmd = ['git', 'rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}']
124*6dbdd20aSAndroid Build Coastguard Worker    res = subprocess.check_output(cmd, text=True, stderr=subprocess.DEVNULL)
125*6dbdd20aSAndroid Build Coastguard Worker    return res.strip()
126*6dbdd20aSAndroid Build Coastguard Worker  except subprocess.CalledProcessError:
127*6dbdd20aSAndroid Build Coastguard Worker    return 'origin/main'
128*6dbdd20aSAndroid Build Coastguard Worker
129*6dbdd20aSAndroid Build Coastguard Worker
130*6dbdd20aSAndroid Build Coastguard Workerif __name__ == '__main__':
131*6dbdd20aSAndroid Build Coastguard Worker  sys.exit(main())
132