• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3# Copyright (C) 2022 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"""Helper functions and types for command processing for difftool."""
18
19
20class CommandInfo:
21  """Contains information about an action commandline."""
22
23  def __init__(self, tool, args):
24    self.tool = tool
25    self.args = args
26
27  def __str__(self):
28    s = "CommandInfo:\n"
29    s += "  Tool:\n"
30    s += "    " + self.tool + "\n"
31    s += "  Args:\n"
32    for x in self.args:
33      s += "    " + x + "\n"
34    return s
35
36
37def parse_flag_groups(args, custom_flag_group=None):
38  """Returns a list of flag groups based on the given args.
39
40  An arg group consists of one-arg flags, two-arg groups, or positional args.
41
42  Positional arguments (for example `a.out`) are returned as strings in the
43    list.
44  One-arg groups consist of a flag with no argument (for example, `--verbose`),
45    and are returned as a tuple of size one in the list.
46  Two-arg groups consist of a flag with a single argument (for example,
47    `--file bar.txt` or `--mode=verbose`),
48    and are returned as a tuple of size two in the list.
49
50  Also accepts an optional function `custom_flag_group` to determine if a
51  single arg comprises a group. (custom_flag_group(x) should return a flag
52  group abiding by the above convention, or None to use non-custom logic.
53  This may be required to accurately parse arg groups. For example, `-a b` may
54  be either a one-arg group `-a` followed by a positonal group `b`, or a two-arg
55  group `-a b`."""
56  flag_groups = []
57
58  i = 0
59  while i < len(args):
60    if custom_flag_group:
61      g = custom_flag_group(args[i])
62      if g is not None:
63        flag_groups += [g]
64        i += 1
65        continue
66
67    g = one_arg_group(args[i])
68    if g is not None:
69      flag_groups += [g]
70      i += 1
71      continue
72
73    # Look for a two-arg group if there are at least 2 elements left.
74    if i < len(args) - 1:
75      g = two_arg_group(args[i], args[i+1])
76      if g is not None:
77        flag_groups += [g]
78        i += 2
79        continue
80
81    # Not a recognized one arg group or two arg group.
82    if args[i].startswith("-"):
83      flag_groups += [(args[i])]
84    else:
85      flag_groups += [args[i]]
86    i += 1
87
88  return flag_groups
89
90
91def remove_hyphens(x):
92  """Returns the given string with leading '--' or '-' removed."""
93  if x.startswith("--"):
94    return x[2:]
95  elif x.startswith("-"):
96    return x[1:]
97  else:
98    return x
99
100
101def two_arg_group(a, b):
102  """Determines whether two consecutive args belong to a single flag group.
103
104  Two arguments belong to a single flag group if the first arg contains
105  a hyphen and the second does not. For example: `-foo bar` is a flag,
106  but `foo bar` and `--foo --bar` are not.
107
108  Returns:
109    A tuple of the two args without hyphens if they belong to a single
110    flag, or None if they do not. """
111  if a.startswith("-") and (not b.startswith("-")):
112    return (remove_hyphens(a), b)
113  else:
114    return None
115
116
117def one_arg_group(x):
118  """Determines whether an arg comprises a complete flag group.
119
120  An argument comprises a single flag group if it is of the form of
121  `-key=value` or `--key=value`.
122
123  Returns:
124    A tuple of `(key, value)` of the flag group, if the arg comprises a
125    complete flag group, or None if it does not."""
126  tokens = x.split("=")
127  if len(tokens) == 2:
128    return (remove_hyphens(tokens[0]), tokens[1])
129  else:
130    return None
131
132
133def is_flag_starts_with(prefix, x):
134  if isinstance(x, tuple):
135    return x[0].startswith(prefix)
136  else:
137    return x.startswith("--" + prefix) or x.startswith("-" + prefix)
138
139
140def flag_repr(x):
141  if isinstance(x, tuple):
142    return f"-{x[0]} {x[1]}"
143  else:
144    return x
145
146