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