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