xref: /aosp_15_r20/tools/asuite/experiments/a/tools/update.py (revision c2e18aaa1096c836b086f94603d04f4eb9cf37f5)
1#!/usr/bin/env python3
2#
3# Copyright 2024 - The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18"""Update Tool."""
19
20import argparse
21
22from core.errors import WorkflowError
23from core.task_runner import Task
24from core.task_runner import TaskRunner
25from tools.update_aliases import get_aliases
26from tools.update_utils import combine_build_commands
27from tools.update_utils import combine_update_commands
28
29
30class Update:
31  """Updates a device."""
32
33  def __init__(self, args):
34    self.args = args
35
36  @classmethod
37  def add_parser(cls, subparsers):
38    """Parse command line update arguments."""
39
40    aliases = get_aliases()
41    epilog = 'Aliases:\n'
42    for alias in get_aliases().keys():
43      name = alias
44      build_commands = (';').join(aliases[name].build())
45      update_commands = (';').join(aliases[name].update())
46      epilog += f'  {name}:\n\t{build_commands}\n\t{update_commands}\n'
47
48    parser = subparsers.add_parser(
49        'update', epilog=epilog, formatter_class=argparse.RawTextHelpFormatter
50    )
51
52    parser.add_argument('alias', nargs='*', default=[], type=str)
53    parser.add_argument(
54        '--build-only',
55        action='store_true',
56        help='only build the specified targets, do not update the device.',
57    )
58    parser.add_argument(
59        '--update-only',
60        action='store_true',
61        help=(
62            'only update the device with prebuilt targets, do not build'
63            ' targets.'
64        ),
65    )
66    parser.add_argument(
67        '--list-aliases',
68        action='store_true',
69        help='list aliases; used for autocomplete',
70    )
71
72  def main(self):
73    """Main entrypoint for Update."""
74
75    if self.args.list_aliases:
76      print(' '.join(get_aliases().keys()))
77      return
78
79    tasks = self.gather_tasks()
80    self.run_tasks(tasks)
81
82  def gather_tasks(self):
83    """Gathers tasks to run based on alias."""
84    tasks = []
85    build_tasks = []
86    update_tasks = []
87
88    requested_aliases = self.args.alias
89    aliases = get_aliases()
90    for a in requested_aliases:
91      if a not in aliases:
92        raise WorkflowError(f'unknown alias: {a}')
93      config = aliases[a]
94      build_tasks += config.build()
95      update_tasks += config.update()
96
97    # combine build tasks
98    build_tasks = combine_build_commands(build_tasks)
99    # combine update tasks
100    update_tasks = combine_update_commands(update_tasks)
101
102    if self.args.build_only:
103      tasks = build_tasks
104    elif self.args.update_only:
105      tasks = update_tasks
106    else:
107      tasks = build_tasks + update_tasks
108
109    if not tasks:
110      # If no tasks run adevice update with a fall back to a full flash.
111      tasks = [
112          'm sync',
113          Task(
114              cmd='adevice update',
115              fall_back_tasks=[
116                  'm droid',
117                  'flashall',
118              ],
119          ),
120      ]
121    return tasks
122
123  def run_tasks(self, tasks):
124    """Runs tasks."""
125    task_runner = TaskRunner()
126    task_runner.quiet = False
127    for task in tasks:
128      if isinstance(task, str):
129        task_runner.add_shell_command_task(task)
130      elif isinstance(task, Task):
131        task_runner.add_shell_command_task(task.cmd, task.fall_back_tasks)
132      else:
133        task_runner.add_task(task)
134    task_runner.start()
135