1 /*
2  * Copyright (C) 2018 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 #ifndef AAPT_COMMAND_H
18 #define AAPT_COMMAND_H
19 
20 #include <functional>
21 #include <optional>
22 #include <ostream>
23 #include <string>
24 #include <unordered_set>
25 #include <vector>
26 
27 #include "androidfw/StringPiece.h"
28 
29 namespace aapt {
30 
31 class Command {
32  public:
Command(android::StringPiece name)33   explicit Command(android::StringPiece name) : name_(name), full_subcommand_name_(name){};
34 
Command(android::StringPiece name,android::StringPiece short_name)35   explicit Command(android::StringPiece name, android::StringPiece short_name)
36       : name_(name), short_name_(short_name), full_subcommand_name_(name){};
37 
38   Command(Command&&) = default;
39   Command& operator=(Command&&) = default;
40 
41   virtual ~Command() = default;
42 
43   // Behavior flags used with the following functions that change how the command flags are parsed
44   // displayed.
45   enum : uint32_t {
46     // Indicates the arguments are file or folder paths. On Windows, paths that exceed the maximum
47     // path length will be converted to use the extended path prefix '//?/'. Without this
48     // conversion, files with long paths cannot be opened.
49     kPath = 1 << 0,
50   };
51 
52   void AddRequiredFlag(android::StringPiece name, android::StringPiece description,
53                        std::string* value, uint32_t flags = 0);
54 
55   void AddRequiredFlagList(android::StringPiece name, android::StringPiece description,
56                            std::vector<std::string>* value, uint32_t flags = 0);
57 
58   void AddOptionalFlag(android::StringPiece name, android::StringPiece description,
59                        std::optional<std::string>* value, uint32_t flags = 0);
60 
61   void AddOptionalFlagList(android::StringPiece name, android::StringPiece description,
62                            std::vector<std::string>* value, uint32_t flags = 0);
63 
64   void AddOptionalFlagList(android::StringPiece name, android::StringPiece description,
65                            std::unordered_set<std::string>* value);
66 
67   void AddOptionalSwitch(android::StringPiece name, android::StringPiece description, bool* value);
68 
69   void AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool experimental = false);
70 
71   void SetDescription(android::StringPiece name);
72 
73   // Prints the help menu of the command.
74   void Usage(std::ostream* out);
75 
76   // Parses the command line arguments, sets the flag variable values, and runs the action of
77   // the command. If the arguments fail to parse to the command and its subcommands, then the action
78   // will not be run and the usage will be printed instead.
79   int Execute(const std::vector<android::StringPiece>& args, std::ostream* outError);
80 
81   // The action to preform when the command is executed.
82   virtual int Action(const std::vector<std::string>& args) = 0;
83 
84  private:
85   struct Flag {
FlagFlag86     explicit Flag(android::StringPiece name, android::StringPiece description,
87                   const bool is_required, const size_t num_args,
88                   std::function<bool(android::StringPiece value)>&& action)
89         : name(name),
90           description(description),
91           is_required(is_required),
92           num_args(num_args),
93           action(std::move(action)) {
94     }
95 
96     const std::string name;
97     const std::string description;
98     const bool is_required;
99     const size_t num_args;
100     const std::function<bool(android::StringPiece value)> action;
101     bool found = false;
102   };
103 
104   std::string name_;
105   std::string short_name_;
106   std::string description_ = "";
107   std::string full_subcommand_name_;
108 
109   std::vector<Flag> flags_;
110   std::vector<std::unique_ptr<Command>> subcommands_;
111   std::vector<std::unique_ptr<Command>> experimental_subcommands_;
112 };
113 
114 }  // namespace aapt
115 
116 #endif  // AAPT_COMMAND_H
117