1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <memory> 20 #include <optional> 21 #include <string> 22 #include <unordered_set> 23 #include <vector> 24 25 #include <cvd_server.pb.h> 26 27 #include "common/libs/utils/result.h" 28 #include "host/commands/cvd/selector/arguments_lexer.h" 29 30 namespace cuttlefish { 31 namespace selector { 32 33 /** 34 * The very first parser for cmdline that separates: 35 * 36 * 1. program name/path 37 * 2. cvd specific options such as --clean, selector options, etc 38 * 3. subcmd 39 * 4. subcmd arguments 40 * 41 * Note that the user's command line arguments are in this order: 42 * $ program_path/name <optional cvd-specific flags> \ 43 * subcmd <optional subcmd arguments> 44 * 45 * For the parser's sake, there are a few more rules. 46 * 47 * 1. All the optional cvd-specific flags should be pre-registered. Usually, 48 * the subcmd arguments do not have to be registered. However, cvd-specific 49 * flags must be. 50 * 51 * E.g. "--clean" is the only registered cvd-specific flag, which happened 52 * to be bool. 53 * These are okay: 54 * cvd --clean start --never-exist-flag 55 * cvd --noclean stop 56 * cvd start 57 * 58 * However, this is not okay: 59 * cvd --daemon start 60 * 61 * 2. -- 62 * E.g. cvd --clean start --have --some --args -- a b c d e 63 * -- is basically for subcommands. cvd itself does not use it. 64 * If -- is within cvd arguments, it is ill-formatted. If it is within 65 * subcommands arguments, we simply forward it to the subtool as is. 66 * 67 */ 68 class ArgumentsSeparator { 69 using CvdProtobufArg = google::protobuf::RepeatedPtrField<std::string>; 70 71 public: 72 struct FlagsRegistration { 73 std::unordered_set<std::string> known_boolean_flags; 74 std::unordered_set<std::string> known_value_flags; 75 std::unordered_set<std::string> valid_subcommands; 76 }; 77 static Result<std::unique_ptr<ArgumentsSeparator>> Parse( 78 const FlagsRegistration& flag_registration, 79 const std::vector<std::string>& input_args); 80 static Result<std::unique_ptr<ArgumentsSeparator>> Parse( 81 const FlagsRegistration& flag_registration, 82 const CvdProtobufArg& input_args); 83 static Result<std::unique_ptr<ArgumentsSeparator>> Parse( 84 const FlagsRegistration& flag_registration, const std::string& input_args, 85 const std::string delim = " "); 86 ProgPath()87 const std::string& ProgPath() const { return prog_path_; } CvdArgs()88 const std::vector<std::string>& CvdArgs() const { return cvd_args_; } SubCmd()89 std::optional<std::string> SubCmd() const { return sub_cmd_; } SubCmdArgs()90 const std::vector<std::string>& SubCmdArgs() const { return sub_cmd_args_; } 91 92 private: 93 ArgumentsSeparator(std::unique_ptr<ArgumentsLexer>&& lexer, 94 const std::vector<std::string>& input_args, 95 const FlagsRegistration& flag_registration); 96 97 bool IsFlag(const ArgType arg_type) const; 98 struct Output { 99 std::string prog_path; 100 std::vector<std::string> cvd_args; 101 std::optional<std::string> sub_cmd; 102 std::vector<std::string> sub_cmd_args; 103 }; 104 Result<void> Parse(); 105 Result<Output> ParseInternal(); 106 107 // internals 108 std::unique_ptr<ArgumentsLexer> lexer_; 109 110 // inputs 111 std::vector<std::string> input_args_; 112 std::unordered_set<std::string> known_boolean_flags_; 113 std::unordered_set<std::string> known_value_flags_; 114 std::unordered_set<std::string> valid_subcmds_; 115 116 // outputs 117 std::string prog_path_; 118 std::vector<std::string> cvd_args_; 119 std::optional<std::string> sub_cmd_; 120 std::vector<std::string> sub_cmd_args_; 121 }; 122 123 } // namespace selector 124 } // namespace cuttlefish 125