xref: /aosp_15_r20/build/make/tools/edit_monitor/main.py (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
1*9e94795aSAndroid Build Coastguard Worker# Copyright 2024, The Android Open Source Project
2*9e94795aSAndroid Build Coastguard Worker#
3*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*9e94795aSAndroid Build Coastguard Worker#
7*9e94795aSAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
8*9e94795aSAndroid Build Coastguard Worker#
9*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*9e94795aSAndroid Build Coastguard Worker# limitations under the License.
14*9e94795aSAndroid Build Coastguard Worker
15*9e94795aSAndroid Build Coastguard Workerimport argparse
16*9e94795aSAndroid Build Coastguard Workerimport logging
17*9e94795aSAndroid Build Coastguard Workerimport os
18*9e94795aSAndroid Build Coastguard Workerimport signal
19*9e94795aSAndroid Build Coastguard Workerimport sys
20*9e94795aSAndroid Build Coastguard Workerimport tempfile
21*9e94795aSAndroid Build Coastguard Worker
22*9e94795aSAndroid Build Coastguard Workerfrom edit_monitor import daemon_manager
23*9e94795aSAndroid Build Coastguard Workerfrom edit_monitor import edit_monitor
24*9e94795aSAndroid Build Coastguard Worker
25*9e94795aSAndroid Build Coastguard Worker
26*9e94795aSAndroid Build Coastguard Workerdef create_arg_parser():
27*9e94795aSAndroid Build Coastguard Worker  """Creates an instance of the default arg parser."""
28*9e94795aSAndroid Build Coastguard Worker
29*9e94795aSAndroid Build Coastguard Worker  parser = argparse.ArgumentParser(
30*9e94795aSAndroid Build Coastguard Worker      description=(
31*9e94795aSAndroid Build Coastguard Worker          'Monitors edits in Android source code and uploads the edit logs.'
32*9e94795aSAndroid Build Coastguard Worker      ),
33*9e94795aSAndroid Build Coastguard Worker      add_help=True,
34*9e94795aSAndroid Build Coastguard Worker      formatter_class=argparse.RawDescriptionHelpFormatter,
35*9e94795aSAndroid Build Coastguard Worker  )
36*9e94795aSAndroid Build Coastguard Worker
37*9e94795aSAndroid Build Coastguard Worker  parser.add_argument(
38*9e94795aSAndroid Build Coastguard Worker      '--path',
39*9e94795aSAndroid Build Coastguard Worker      type=str,
40*9e94795aSAndroid Build Coastguard Worker      required=True,
41*9e94795aSAndroid Build Coastguard Worker      help='Root path to monitor the edit events.',
42*9e94795aSAndroid Build Coastguard Worker  )
43*9e94795aSAndroid Build Coastguard Worker
44*9e94795aSAndroid Build Coastguard Worker  parser.add_argument(
45*9e94795aSAndroid Build Coastguard Worker      '--dry_run',
46*9e94795aSAndroid Build Coastguard Worker      action='store_true',
47*9e94795aSAndroid Build Coastguard Worker      help='Dry run the edit monitor. This starts the edit monitor process without actually send the edit logs to clearcut.',
48*9e94795aSAndroid Build Coastguard Worker  )
49*9e94795aSAndroid Build Coastguard Worker
50*9e94795aSAndroid Build Coastguard Worker  parser.add_argument(
51*9e94795aSAndroid Build Coastguard Worker      '--force_cleanup',
52*9e94795aSAndroid Build Coastguard Worker      action='store_true',
53*9e94795aSAndroid Build Coastguard Worker      help=(
54*9e94795aSAndroid Build Coastguard Worker          'Instead of start a new edit monitor, force stop all existing edit'
55*9e94795aSAndroid Build Coastguard Worker          ' monitors in the system. This option is only used in emergent cases'
56*9e94795aSAndroid Build Coastguard Worker          ' when we want to prevent user damage by the edit monitor.'
57*9e94795aSAndroid Build Coastguard Worker      ),
58*9e94795aSAndroid Build Coastguard Worker  )
59*9e94795aSAndroid Build Coastguard Worker
60*9e94795aSAndroid Build Coastguard Worker  parser.add_argument(
61*9e94795aSAndroid Build Coastguard Worker      '--verbose',
62*9e94795aSAndroid Build Coastguard Worker      action='store_true',
63*9e94795aSAndroid Build Coastguard Worker      help=(
64*9e94795aSAndroid Build Coastguard Worker          'Log verbose info in the log file for debugging purpose.'
65*9e94795aSAndroid Build Coastguard Worker      ),
66*9e94795aSAndroid Build Coastguard Worker  )
67*9e94795aSAndroid Build Coastguard Worker
68*9e94795aSAndroid Build Coastguard Worker  return parser
69*9e94795aSAndroid Build Coastguard Worker
70*9e94795aSAndroid Build Coastguard Worker
71*9e94795aSAndroid Build Coastguard Workerdef configure_logging(verbose=False):
72*9e94795aSAndroid Build Coastguard Worker  root_logging_dir = tempfile.mkdtemp(prefix='edit_monitor_')
73*9e94795aSAndroid Build Coastguard Worker  _, log_path = tempfile.mkstemp(dir=root_logging_dir, suffix='.log')
74*9e94795aSAndroid Build Coastguard Worker
75*9e94795aSAndroid Build Coastguard Worker
76*9e94795aSAndroid Build Coastguard Worker  log_fmt = '%(asctime)s.%(msecs)03d %(filename)s:%(lineno)s:%(levelname)s: %(message)s'
77*9e94795aSAndroid Build Coastguard Worker  date_fmt = '%Y-%m-%d %H:%M:%S'
78*9e94795aSAndroid Build Coastguard Worker  log_level = logging.DEBUG if verbose else logging.INFO
79*9e94795aSAndroid Build Coastguard Worker
80*9e94795aSAndroid Build Coastguard Worker  logging.basicConfig(
81*9e94795aSAndroid Build Coastguard Worker      filename=log_path, level=log_level, format=log_fmt, datefmt=date_fmt
82*9e94795aSAndroid Build Coastguard Worker  )
83*9e94795aSAndroid Build Coastguard Worker  # Filter out logs from inotify_buff to prevent log pollution.
84*9e94795aSAndroid Build Coastguard Worker  logging.getLogger('watchdog.observers.inotify_buffer').addFilter(
85*9e94795aSAndroid Build Coastguard Worker      lambda record: record.filename != 'inotify_buffer.py')
86*9e94795aSAndroid Build Coastguard Worker  print(f'logging to file {log_path}')
87*9e94795aSAndroid Build Coastguard Worker
88*9e94795aSAndroid Build Coastguard Worker
89*9e94795aSAndroid Build Coastguard Workerdef term_signal_handler(_signal_number, _frame):
90*9e94795aSAndroid Build Coastguard Worker  logging.info('Process %d received SIGTERM, Terminating...', os.getpid())
91*9e94795aSAndroid Build Coastguard Worker  sys.exit(0)
92*9e94795aSAndroid Build Coastguard Worker
93*9e94795aSAndroid Build Coastguard Worker
94*9e94795aSAndroid Build Coastguard Workerdef main(argv: list[str]):
95*9e94795aSAndroid Build Coastguard Worker  args = create_arg_parser().parse_args(argv[1:])
96*9e94795aSAndroid Build Coastguard Worker  configure_logging(args.verbose)
97*9e94795aSAndroid Build Coastguard Worker  if args.dry_run:
98*9e94795aSAndroid Build Coastguard Worker    logging.info('This is a dry run.')
99*9e94795aSAndroid Build Coastguard Worker  dm = daemon_manager.DaemonManager(
100*9e94795aSAndroid Build Coastguard Worker      binary_path=argv[0],
101*9e94795aSAndroid Build Coastguard Worker      daemon_target=edit_monitor.start,
102*9e94795aSAndroid Build Coastguard Worker      daemon_args=(args.path, args.dry_run),
103*9e94795aSAndroid Build Coastguard Worker  )
104*9e94795aSAndroid Build Coastguard Worker
105*9e94795aSAndroid Build Coastguard Worker  try:
106*9e94795aSAndroid Build Coastguard Worker    if args.force_cleanup:
107*9e94795aSAndroid Build Coastguard Worker      dm.cleanup()
108*9e94795aSAndroid Build Coastguard Worker    else:
109*9e94795aSAndroid Build Coastguard Worker      dm.start()
110*9e94795aSAndroid Build Coastguard Worker      dm.monitor_daemon()
111*9e94795aSAndroid Build Coastguard Worker  except Exception:
112*9e94795aSAndroid Build Coastguard Worker    logging.exception('Unexpected exception raised when run daemon.')
113*9e94795aSAndroid Build Coastguard Worker  finally:
114*9e94795aSAndroid Build Coastguard Worker    dm.stop()
115*9e94795aSAndroid Build Coastguard Worker
116*9e94795aSAndroid Build Coastguard Worker
117*9e94795aSAndroid Build Coastguard Workerif __name__ == '__main__':
118*9e94795aSAndroid Build Coastguard Worker  signal.signal(signal.SIGTERM, term_signal_handler)
119*9e94795aSAndroid Build Coastguard Worker  main(sys.argv)
120