Loading tools/aapt2/cmd/Command.cpp +62 −43 Original line number Diff line number Diff line Loading @@ -21,80 +21,97 @@ #include <string> #include <vector> #include "android-base/stringprintf.h" #include "android-base/utf8.h" #include "androidfw/StringPiece.h" #include "util/Util.h" using android::base::StringPrintf; using android::StringPiece; namespace aapt { void Command::AddRequiredFlag(const StringPiece& name, const StringPiece& description, std::string* value) { auto func = [value](const StringPiece& arg) -> bool { *value = arg.to_string(); std::string GetSafePath(const StringPiece& arg) { #ifdef _WIN32 // If the path exceeds the maximum path length for Windows, encode the path using the // extended-length prefix std::wstring path16; CHECK(android::base::UTF8PathToWindowsLongPath(arg.data(), &path16)) << "Failed to convert file path to UTF-16: file path " << arg.data(); std::string path8; CHECK(android::base::WideToUTF8(path16, &path8)) << "Failed to convert file path back to UTF-8: file path " << arg.data(); return path8; #else return arg.to_string(); #endif } void Command::AddRequiredFlag(const StringPiece& name, const StringPiece& description, std::string* value, uint32_t flags) { auto func = [value, flags](const StringPiece& arg) -> bool { *value = (flags & Command::kPath) ? GetSafePath(arg) : arg.to_string(); return true; }; flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false}); flags_.emplace_back(Flag(name, description, /* required */ true, /* num_args */ 1, func)); } void Command::AddRequiredFlagList(const StringPiece& name, const StringPiece& description, std::vector<std::string>* value) { auto func = [value](const StringPiece& arg) -> bool { value->push_back(arg.to_string()); void Command::AddRequiredFlagList(const StringPiece& name, const StringPiece& description, std::vector<std::string>* value, uint32_t flags) { auto func = [value, flags](const StringPiece& arg) -> bool { value->push_back((flags & Command::kPath) ? GetSafePath(arg) : arg.to_string()); return true; }; flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false}); flags_.emplace_back(Flag(name, description, /* required */ true, /* num_args */ 1, func)); } void Command::AddOptionalFlag(const StringPiece& name, const StringPiece& description, Maybe<std::string>* value) { auto func = [value](const StringPiece& arg) -> bool { *value = arg.to_string(); void Command::AddOptionalFlag(const StringPiece& name, const StringPiece& description, Maybe<std::string>* value, uint32_t flags) { auto func = [value, flags](const StringPiece& arg) -> bool { *value = (flags & Command::kPath) ? GetSafePath(arg) : arg.to_string(); return true; }; flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false}); flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func)); } void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description, std::vector<std::string>* value) { auto func = [value](const StringPiece& arg) -> bool { value->push_back(arg.to_string()); void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description, std::vector<std::string>* value, uint32_t flags) { auto func = [value, flags](const StringPiece& arg) -> bool { value->push_back((flags & Command::kPath) ? GetSafePath(arg) : arg.to_string()); return true; }; flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false}); flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func)); } void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description, void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description, std::unordered_set<std::string>* value) { auto func = [value](const StringPiece& arg) -> bool { value->insert(arg.to_string()); return true; }; flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false}); flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func)); } void Command::AddOptionalSwitch(const StringPiece& name, const StringPiece& description, bool* value) { void Command::AddOptionalSwitch(const StringPiece& name, const StringPiece& description, bool* value) { auto func = [value](const StringPiece& arg) -> bool { *value = true; return true; }; flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 0, false}); flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 0, func)); } void Command::AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool experimental) { subcommand->fullname_ = name_ + " " + subcommand->name_; subcommand->full_subcommand_name_ = StringPrintf("%s %s", name_.data(), subcommand->name_.data()); if (experimental) { experimental_subcommands_.push_back(std::move(subcommand)); } else { Loading @@ -102,14 +119,14 @@ void Command::AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool } } void Command::SetDescription(const android::StringPiece& description) { void Command::SetDescription(const StringPiece& description) { description_ = description.to_string(); } void Command::Usage(std::ostream* out) { constexpr size_t kWidth = 50; *out << fullname_; *out << full_subcommand_name_; if (!subcommands_.empty()) { *out << " [subcommand]"; Loading @@ -117,7 +134,7 @@ void Command::Usage(std::ostream* out) { *out << " [options]"; for (const Flag& flag : flags_) { if (flag.required) { if (flag.is_required) { *out << " " << flag.name << " arg"; } } Loading Loading @@ -160,29 +177,31 @@ void Command::Usage(std::ostream* out) { out->flush(); } int Command::Execute(const std::vector<android::StringPiece>& args, std::ostream* out_error) { int Command::Execute(const std::vector<StringPiece>& args, std::ostream* out_error) { std::vector<std::string> file_args; for (size_t i = 0; i < args.size(); i++) { StringPiece arg = args[i]; const StringPiece& arg = args[i]; if (*(arg.data()) != '-') { // Continue parsing as the subcommand if the first argument matches one of the subcommands if (i == 0) { for (auto& subcommand : subcommands_) { if (arg == subcommand->name_ || arg==subcommand->short_name_) { if (arg == subcommand->name_ || (!subcommand->short_name_.empty() && arg == subcommand->short_name_)) { return subcommand->Execute( std::vector<android::StringPiece>(args.begin() + 1, args.end()), out_error); std::vector<StringPiece>(args.begin() + 1, args.end()), out_error); } } for (auto& subcommand : experimental_subcommands_) { if (arg == subcommand->name_ || arg==subcommand->short_name_) { if (arg == subcommand->name_ || (!subcommand->short_name_.empty() && arg == subcommand->short_name_)) { return subcommand->Execute( std::vector<android::StringPiece>(args.begin() + 1, args.end()), out_error); std::vector<StringPiece>(args.begin() + 1, args.end()), out_error); } } } file_args.push_back(arg.to_string()); file_args.push_back(GetSafePath(arg)); continue; } Loading @@ -205,7 +224,7 @@ int Command::Execute(const std::vector<android::StringPiece>& args, std::ostream } else { flag.action({}); } flag.parsed = true; flag.found = true; match = true; break; } Loading @@ -219,7 +238,7 @@ int Command::Execute(const std::vector<android::StringPiece>& args, std::ostream } for (const Flag& flag : flags_) { if (flag.required && !flag.parsed) { if (flag.is_required && !flag.found) { *out_error << "missing required flag " << flag.name << "\n\n"; Usage(out_error); return 1; Loading tools/aapt2/cmd/Command.h +55 −27 Original line number Diff line number Diff line Loading @@ -32,55 +32,83 @@ namespace aapt { class Command { public: explicit Command(const android::StringPiece& name) : name_(name.to_string()), fullname_(name.to_string()) { } short_name_(""), full_subcommand_name_(name.to_string()) {} explicit Command(const android::StringPiece& name, const android::StringPiece& short_name) : name_(name.to_string()), short_name_(short_name.to_string()), fullname_(name.to_string()) {} : name_(name.to_string()), short_name_(short_name.to_string()), full_subcommand_name_(name.to_string()) {} virtual ~Command() = default; // Behavior flags used with the following functions that change how the command flags are parsed // displayed. enum : uint32_t { // Indicates the arguments are file or folder paths. On Windows, paths that exceed the maximum // path length will be converted to use the extended path prefix '//?/'. Without this // conversion, files with long paths cannot be opened. kPath = 1 << 0, }; void AddRequiredFlag(const android::StringPiece& name, const android::StringPiece& description, std::string* value); void AddRequiredFlagList(const android::StringPiece& name, const android::StringPiece& description, std::vector<std::string>* value); std::string* value, uint32_t flags = 0); void AddRequiredFlagList(const android::StringPiece& name, const android::StringPiece& description, std::vector<std::string>* value, uint32_t flags = 0); void AddOptionalFlag(const android::StringPiece& name, const android::StringPiece& description, Maybe<std::string>* value); Maybe<std::string>* value, uint32_t flags = 0); void AddOptionalFlagList(const android::StringPiece& name, const android::StringPiece& description, std::vector<std::string>* value); const android::StringPiece& description, std::vector<std::string>* value, uint32_t flags = 0); void AddOptionalFlagList(const android::StringPiece& name, const android::StringPiece& description, std::unordered_set<std::string>* value); const android::StringPiece& description, std::unordered_set<std::string>* value); void AddOptionalSwitch(const android::StringPiece& name, const android::StringPiece& description, bool* value); void AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool experimental = false); void SetDescription(const android::StringPiece& name); /** Prints the help menu of the command. */ // Prints the help menu of the command. void Usage(std::ostream* out); /** * Parses the command line arguments, sets the flag variable values, and runs the action of * the command. If the arguments fail to parse to the command and its subcommands, then the action * will not be run and the usage will be printed instead. **/ // Parses the command line arguments, sets the flag variable values, and runs the action of // the command. If the arguments fail to parse to the command and its subcommands, then the action // will not be run and the usage will be printed instead. int Execute(const std::vector<android::StringPiece>& args, std::ostream* outError); /** The action to preform when the command is executed. */ // The action to preform when the command is executed. virtual int Action(const std::vector<std::string>& args) = 0; private: struct Flag { std::string name; std::string description; std::function<bool(const android::StringPiece& value)> action; bool required; size_t num_args; DISALLOW_COPY_AND_ASSIGN(Command); bool parsed; struct Flag { explicit Flag(const android::StringPiece& name, const android::StringPiece& description, const bool is_required, const size_t num_args, std::function<bool(const android::StringPiece& value)>&& action) : name(name.to_string()), description(description.to_string()), is_required(is_required), num_args(num_args), action(std::move(action)) {} const std::string name; const std::string description; const bool is_required; const size_t num_args; const std::function<bool(const android::StringPiece& value)> action; bool found = false; }; std::string description_; std::string name_; std::string short_name_; std::string fullname_; const std::string name_; const std::string short_name_; std::string description_ = ""; std::string full_subcommand_name_; std::vector<Flag> flags_; std::vector<std::unique_ptr<Command>> subcommands_; std::vector<std::unique_ptr<Command>> experimental_subcommands_; Loading tools/aapt2/cmd/Command_test.cpp 0 → 100644 +97 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Command.h" #include "test/Test.h" using ::testing::Eq; namespace aapt { class TestCommand : public Command { public: explicit TestCommand() : Command("command") {} int Action(const std::vector<std::string>& args) override { args_ = args; return 0; } std::vector<std::string> args_; }; #ifdef _WIN32 TEST(CommandTest, LongFullyQualifiedPathWindows) { TestCommand command; std::string required_flag; command.AddRequiredFlag("--rflag", "", &required_flag, Command::kPath); Maybe<std::string> optional_flag; command.AddOptionalFlag("--oflag", "", &optional_flag, Command::kPath); std::vector<std::string> required_flag_list; command.AddRequiredFlagList("--rlflag", "", &required_flag_list, Command::kPath); std::vector<std::string> optional_flag_list; command.AddOptionalFlagList("--olflag", "", &optional_flag_list, Command::kPath); std::string non_path_flag; command.AddRequiredFlag("--nflag", "", &non_path_flag); const std::string kLongPath = "C:\\Users\\jedo\\_bazel_jedo\\vcmdctjv\\execroot\\__main__\\_tmp" "\\6767b4778f8798efc0f784ee74fa70ee\\tests\\testApksAr8c7560a9a65" "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build" "\\intermediates\\processed_res\\minified\\processMinifiedResources" "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build" "\\intermediates\\processed_res\\minified\\processMinifiedResources" "\\out\\resources-minified.ap_"; const std::string kExpected = "\\\\?\\C:\\Users\\jedo\\_bazel_jedo\\vcmdctjv\\execroot\\__main__\\_tmp" "\\6767b4778f8798efc0f784ee74fa70ee\\tests\\testApksAr8c7560a9a65" "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build" "\\intermediates\\processed_res\\minified\\processMinifiedResources" "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build" "\\intermediates\\processed_res\\minified\\processMinifiedResources" "\\out\\resources-minified.ap_"; ASSERT_THAT(command.Execute({"--rflag", kLongPath, "--oflag", kLongPath, "--rlflag", kLongPath, "--rlflag", kLongPath, "--olflag", kLongPath, "--olflag", kLongPath, "--nflag", kLongPath, kLongPath, kLongPath}, &std::cerr), Eq(0)); ASSERT_THAT(required_flag, Eq(kExpected)); ASSERT_THAT(optional_flag, Eq(kExpected)); ASSERT_THAT(required_flag_list.size(), Eq(2)); ASSERT_THAT(required_flag_list[0], Eq(kExpected)); ASSERT_THAT(required_flag_list[1], Eq(kExpected)); ASSERT_THAT(optional_flag_list.size(), Eq(2)); ASSERT_THAT(optional_flag_list[0], Eq(kExpected)); ASSERT_THAT(optional_flag_list[1], Eq(kExpected)); // File arguments should also be converted to use the long path prefix ASSERT_THAT(command.args_.size(), Eq(2)); ASSERT_THAT(command.args_[0], Eq(kExpected)); ASSERT_THAT(command.args_[1], Eq(kExpected)); // Do not convert flags that are not marged as paths ASSERT_THAT(non_path_flag, Eq(kLongPath)); } #endif } // namespace aapt No newline at end of file tools/aapt2/cmd/Compile.h +7 −6 Original line number Diff line number Diff line Loading @@ -44,13 +44,13 @@ class CompileCommand : public Command { explicit CompileCommand(IDiagnostics* diagnostic) : Command("compile", "c"), diagnostic_(diagnostic) { SetDescription("Compiles resources to be linked into an apk."); AddRequiredFlag("-o", "Output path", &options_.output_path); AddOptionalFlag("--dir", "Directory to scan for resources", &options_.res_dir); AddRequiredFlag("-o", "Output path", &options_.output_path, Command::kPath); AddOptionalFlag("--dir", "Directory to scan for resources", &options_.res_dir, Command::kPath); AddOptionalFlag("--zip", "Zip file containing the res directory to scan for resources", &options_.res_zip); &options_.res_zip, Command::kPath); AddOptionalFlag("--output-text-symbols", "Generates a text file containing the resource symbols in the\n" "specified file", &options_.generate_text_symbols_path); "specified file", &options_.generate_text_symbols_path, Command::kPath); AddOptionalSwitch("--pseudo-localize", "Generate resources for pseudo-locales " "(en-XA and ar-XB)", &options_.pseudolocalize); AddOptionalSwitch("--no-crunch", "Disables PNG processing", &options_.no_png_crunch); Loading @@ -70,8 +70,9 @@ class CompileCommand : public Command { Maybe<std::string> visibility_; }; int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* output_writer, CompileOptions& options); int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* output_writer, CompileOptions& options); }// namespace aapt #endif //AAPT2_COMPILE_H tools/aapt2/cmd/Convert.h +1 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ class ConvertCommand : public Command { public: explicit ConvertCommand() : Command("convert") { SetDescription("Converts an apk between binary and proto formats."); AddRequiredFlag("-o", "Output path", &output_path_); AddRequiredFlag("-o", "Output path", &output_path_, Command::kPath); AddOptionalFlag("--output-format", android::base::StringPrintf("Format of the output. " "Accepted values are '%s' and '%s'. When not set, defaults to '%s'.", kOutputFormatProto, kOutputFormatBinary, kOutputFormatBinary), &output_format_); Loading Loading
tools/aapt2/cmd/Command.cpp +62 −43 Original line number Diff line number Diff line Loading @@ -21,80 +21,97 @@ #include <string> #include <vector> #include "android-base/stringprintf.h" #include "android-base/utf8.h" #include "androidfw/StringPiece.h" #include "util/Util.h" using android::base::StringPrintf; using android::StringPiece; namespace aapt { void Command::AddRequiredFlag(const StringPiece& name, const StringPiece& description, std::string* value) { auto func = [value](const StringPiece& arg) -> bool { *value = arg.to_string(); std::string GetSafePath(const StringPiece& arg) { #ifdef _WIN32 // If the path exceeds the maximum path length for Windows, encode the path using the // extended-length prefix std::wstring path16; CHECK(android::base::UTF8PathToWindowsLongPath(arg.data(), &path16)) << "Failed to convert file path to UTF-16: file path " << arg.data(); std::string path8; CHECK(android::base::WideToUTF8(path16, &path8)) << "Failed to convert file path back to UTF-8: file path " << arg.data(); return path8; #else return arg.to_string(); #endif } void Command::AddRequiredFlag(const StringPiece& name, const StringPiece& description, std::string* value, uint32_t flags) { auto func = [value, flags](const StringPiece& arg) -> bool { *value = (flags & Command::kPath) ? GetSafePath(arg) : arg.to_string(); return true; }; flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false}); flags_.emplace_back(Flag(name, description, /* required */ true, /* num_args */ 1, func)); } void Command::AddRequiredFlagList(const StringPiece& name, const StringPiece& description, std::vector<std::string>* value) { auto func = [value](const StringPiece& arg) -> bool { value->push_back(arg.to_string()); void Command::AddRequiredFlagList(const StringPiece& name, const StringPiece& description, std::vector<std::string>* value, uint32_t flags) { auto func = [value, flags](const StringPiece& arg) -> bool { value->push_back((flags & Command::kPath) ? GetSafePath(arg) : arg.to_string()); return true; }; flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false}); flags_.emplace_back(Flag(name, description, /* required */ true, /* num_args */ 1, func)); } void Command::AddOptionalFlag(const StringPiece& name, const StringPiece& description, Maybe<std::string>* value) { auto func = [value](const StringPiece& arg) -> bool { *value = arg.to_string(); void Command::AddOptionalFlag(const StringPiece& name, const StringPiece& description, Maybe<std::string>* value, uint32_t flags) { auto func = [value, flags](const StringPiece& arg) -> bool { *value = (flags & Command::kPath) ? GetSafePath(arg) : arg.to_string(); return true; }; flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false}); flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func)); } void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description, std::vector<std::string>* value) { auto func = [value](const StringPiece& arg) -> bool { value->push_back(arg.to_string()); void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description, std::vector<std::string>* value, uint32_t flags) { auto func = [value, flags](const StringPiece& arg) -> bool { value->push_back((flags & Command::kPath) ? GetSafePath(arg) : arg.to_string()); return true; }; flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false}); flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func)); } void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description, void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description, std::unordered_set<std::string>* value) { auto func = [value](const StringPiece& arg) -> bool { value->insert(arg.to_string()); return true; }; flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false}); flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func)); } void Command::AddOptionalSwitch(const StringPiece& name, const StringPiece& description, bool* value) { void Command::AddOptionalSwitch(const StringPiece& name, const StringPiece& description, bool* value) { auto func = [value](const StringPiece& arg) -> bool { *value = true; return true; }; flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 0, false}); flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 0, func)); } void Command::AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool experimental) { subcommand->fullname_ = name_ + " " + subcommand->name_; subcommand->full_subcommand_name_ = StringPrintf("%s %s", name_.data(), subcommand->name_.data()); if (experimental) { experimental_subcommands_.push_back(std::move(subcommand)); } else { Loading @@ -102,14 +119,14 @@ void Command::AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool } } void Command::SetDescription(const android::StringPiece& description) { void Command::SetDescription(const StringPiece& description) { description_ = description.to_string(); } void Command::Usage(std::ostream* out) { constexpr size_t kWidth = 50; *out << fullname_; *out << full_subcommand_name_; if (!subcommands_.empty()) { *out << " [subcommand]"; Loading @@ -117,7 +134,7 @@ void Command::Usage(std::ostream* out) { *out << " [options]"; for (const Flag& flag : flags_) { if (flag.required) { if (flag.is_required) { *out << " " << flag.name << " arg"; } } Loading Loading @@ -160,29 +177,31 @@ void Command::Usage(std::ostream* out) { out->flush(); } int Command::Execute(const std::vector<android::StringPiece>& args, std::ostream* out_error) { int Command::Execute(const std::vector<StringPiece>& args, std::ostream* out_error) { std::vector<std::string> file_args; for (size_t i = 0; i < args.size(); i++) { StringPiece arg = args[i]; const StringPiece& arg = args[i]; if (*(arg.data()) != '-') { // Continue parsing as the subcommand if the first argument matches one of the subcommands if (i == 0) { for (auto& subcommand : subcommands_) { if (arg == subcommand->name_ || arg==subcommand->short_name_) { if (arg == subcommand->name_ || (!subcommand->short_name_.empty() && arg == subcommand->short_name_)) { return subcommand->Execute( std::vector<android::StringPiece>(args.begin() + 1, args.end()), out_error); std::vector<StringPiece>(args.begin() + 1, args.end()), out_error); } } for (auto& subcommand : experimental_subcommands_) { if (arg == subcommand->name_ || arg==subcommand->short_name_) { if (arg == subcommand->name_ || (!subcommand->short_name_.empty() && arg == subcommand->short_name_)) { return subcommand->Execute( std::vector<android::StringPiece>(args.begin() + 1, args.end()), out_error); std::vector<StringPiece>(args.begin() + 1, args.end()), out_error); } } } file_args.push_back(arg.to_string()); file_args.push_back(GetSafePath(arg)); continue; } Loading @@ -205,7 +224,7 @@ int Command::Execute(const std::vector<android::StringPiece>& args, std::ostream } else { flag.action({}); } flag.parsed = true; flag.found = true; match = true; break; } Loading @@ -219,7 +238,7 @@ int Command::Execute(const std::vector<android::StringPiece>& args, std::ostream } for (const Flag& flag : flags_) { if (flag.required && !flag.parsed) { if (flag.is_required && !flag.found) { *out_error << "missing required flag " << flag.name << "\n\n"; Usage(out_error); return 1; Loading
tools/aapt2/cmd/Command.h +55 −27 Original line number Diff line number Diff line Loading @@ -32,55 +32,83 @@ namespace aapt { class Command { public: explicit Command(const android::StringPiece& name) : name_(name.to_string()), fullname_(name.to_string()) { } short_name_(""), full_subcommand_name_(name.to_string()) {} explicit Command(const android::StringPiece& name, const android::StringPiece& short_name) : name_(name.to_string()), short_name_(short_name.to_string()), fullname_(name.to_string()) {} : name_(name.to_string()), short_name_(short_name.to_string()), full_subcommand_name_(name.to_string()) {} virtual ~Command() = default; // Behavior flags used with the following functions that change how the command flags are parsed // displayed. enum : uint32_t { // Indicates the arguments are file or folder paths. On Windows, paths that exceed the maximum // path length will be converted to use the extended path prefix '//?/'. Without this // conversion, files with long paths cannot be opened. kPath = 1 << 0, }; void AddRequiredFlag(const android::StringPiece& name, const android::StringPiece& description, std::string* value); void AddRequiredFlagList(const android::StringPiece& name, const android::StringPiece& description, std::vector<std::string>* value); std::string* value, uint32_t flags = 0); void AddRequiredFlagList(const android::StringPiece& name, const android::StringPiece& description, std::vector<std::string>* value, uint32_t flags = 0); void AddOptionalFlag(const android::StringPiece& name, const android::StringPiece& description, Maybe<std::string>* value); Maybe<std::string>* value, uint32_t flags = 0); void AddOptionalFlagList(const android::StringPiece& name, const android::StringPiece& description, std::vector<std::string>* value); const android::StringPiece& description, std::vector<std::string>* value, uint32_t flags = 0); void AddOptionalFlagList(const android::StringPiece& name, const android::StringPiece& description, std::unordered_set<std::string>* value); const android::StringPiece& description, std::unordered_set<std::string>* value); void AddOptionalSwitch(const android::StringPiece& name, const android::StringPiece& description, bool* value); void AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool experimental = false); void SetDescription(const android::StringPiece& name); /** Prints the help menu of the command. */ // Prints the help menu of the command. void Usage(std::ostream* out); /** * Parses the command line arguments, sets the flag variable values, and runs the action of * the command. If the arguments fail to parse to the command and its subcommands, then the action * will not be run and the usage will be printed instead. **/ // Parses the command line arguments, sets the flag variable values, and runs the action of // the command. If the arguments fail to parse to the command and its subcommands, then the action // will not be run and the usage will be printed instead. int Execute(const std::vector<android::StringPiece>& args, std::ostream* outError); /** The action to preform when the command is executed. */ // The action to preform when the command is executed. virtual int Action(const std::vector<std::string>& args) = 0; private: struct Flag { std::string name; std::string description; std::function<bool(const android::StringPiece& value)> action; bool required; size_t num_args; DISALLOW_COPY_AND_ASSIGN(Command); bool parsed; struct Flag { explicit Flag(const android::StringPiece& name, const android::StringPiece& description, const bool is_required, const size_t num_args, std::function<bool(const android::StringPiece& value)>&& action) : name(name.to_string()), description(description.to_string()), is_required(is_required), num_args(num_args), action(std::move(action)) {} const std::string name; const std::string description; const bool is_required; const size_t num_args; const std::function<bool(const android::StringPiece& value)> action; bool found = false; }; std::string description_; std::string name_; std::string short_name_; std::string fullname_; const std::string name_; const std::string short_name_; std::string description_ = ""; std::string full_subcommand_name_; std::vector<Flag> flags_; std::vector<std::unique_ptr<Command>> subcommands_; std::vector<std::unique_ptr<Command>> experimental_subcommands_; Loading
tools/aapt2/cmd/Command_test.cpp 0 → 100644 +97 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Command.h" #include "test/Test.h" using ::testing::Eq; namespace aapt { class TestCommand : public Command { public: explicit TestCommand() : Command("command") {} int Action(const std::vector<std::string>& args) override { args_ = args; return 0; } std::vector<std::string> args_; }; #ifdef _WIN32 TEST(CommandTest, LongFullyQualifiedPathWindows) { TestCommand command; std::string required_flag; command.AddRequiredFlag("--rflag", "", &required_flag, Command::kPath); Maybe<std::string> optional_flag; command.AddOptionalFlag("--oflag", "", &optional_flag, Command::kPath); std::vector<std::string> required_flag_list; command.AddRequiredFlagList("--rlflag", "", &required_flag_list, Command::kPath); std::vector<std::string> optional_flag_list; command.AddOptionalFlagList("--olflag", "", &optional_flag_list, Command::kPath); std::string non_path_flag; command.AddRequiredFlag("--nflag", "", &non_path_flag); const std::string kLongPath = "C:\\Users\\jedo\\_bazel_jedo\\vcmdctjv\\execroot\\__main__\\_tmp" "\\6767b4778f8798efc0f784ee74fa70ee\\tests\\testApksAr8c7560a9a65" "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build" "\\intermediates\\processed_res\\minified\\processMinifiedResources" "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build" "\\intermediates\\processed_res\\minified\\processMinifiedResources" "\\out\\resources-minified.ap_"; const std::string kExpected = "\\\\?\\C:\\Users\\jedo\\_bazel_jedo\\vcmdctjv\\execroot\\__main__\\_tmp" "\\6767b4778f8798efc0f784ee74fa70ee\\tests\\testApksAr8c7560a9a65" "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build" "\\intermediates\\processed_res\\minified\\processMinifiedResources" "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build" "\\intermediates\\processed_res\\minified\\processMinifiedResources" "\\out\\resources-minified.ap_"; ASSERT_THAT(command.Execute({"--rflag", kLongPath, "--oflag", kLongPath, "--rlflag", kLongPath, "--rlflag", kLongPath, "--olflag", kLongPath, "--olflag", kLongPath, "--nflag", kLongPath, kLongPath, kLongPath}, &std::cerr), Eq(0)); ASSERT_THAT(required_flag, Eq(kExpected)); ASSERT_THAT(optional_flag, Eq(kExpected)); ASSERT_THAT(required_flag_list.size(), Eq(2)); ASSERT_THAT(required_flag_list[0], Eq(kExpected)); ASSERT_THAT(required_flag_list[1], Eq(kExpected)); ASSERT_THAT(optional_flag_list.size(), Eq(2)); ASSERT_THAT(optional_flag_list[0], Eq(kExpected)); ASSERT_THAT(optional_flag_list[1], Eq(kExpected)); // File arguments should also be converted to use the long path prefix ASSERT_THAT(command.args_.size(), Eq(2)); ASSERT_THAT(command.args_[0], Eq(kExpected)); ASSERT_THAT(command.args_[1], Eq(kExpected)); // Do not convert flags that are not marged as paths ASSERT_THAT(non_path_flag, Eq(kLongPath)); } #endif } // namespace aapt No newline at end of file
tools/aapt2/cmd/Compile.h +7 −6 Original line number Diff line number Diff line Loading @@ -44,13 +44,13 @@ class CompileCommand : public Command { explicit CompileCommand(IDiagnostics* diagnostic) : Command("compile", "c"), diagnostic_(diagnostic) { SetDescription("Compiles resources to be linked into an apk."); AddRequiredFlag("-o", "Output path", &options_.output_path); AddOptionalFlag("--dir", "Directory to scan for resources", &options_.res_dir); AddRequiredFlag("-o", "Output path", &options_.output_path, Command::kPath); AddOptionalFlag("--dir", "Directory to scan for resources", &options_.res_dir, Command::kPath); AddOptionalFlag("--zip", "Zip file containing the res directory to scan for resources", &options_.res_zip); &options_.res_zip, Command::kPath); AddOptionalFlag("--output-text-symbols", "Generates a text file containing the resource symbols in the\n" "specified file", &options_.generate_text_symbols_path); "specified file", &options_.generate_text_symbols_path, Command::kPath); AddOptionalSwitch("--pseudo-localize", "Generate resources for pseudo-locales " "(en-XA and ar-XB)", &options_.pseudolocalize); AddOptionalSwitch("--no-crunch", "Disables PNG processing", &options_.no_png_crunch); Loading @@ -70,8 +70,9 @@ class CompileCommand : public Command { Maybe<std::string> visibility_; }; int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* output_writer, CompileOptions& options); int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* output_writer, CompileOptions& options); }// namespace aapt #endif //AAPT2_COMPILE_H
tools/aapt2/cmd/Convert.h +1 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ class ConvertCommand : public Command { public: explicit ConvertCommand() : Command("convert") { SetDescription("Converts an apk between binary and proto formats."); AddRequiredFlag("-o", "Output path", &output_path_); AddRequiredFlag("-o", "Output path", &output_path_, Command::kPath); AddOptionalFlag("--output-format", android::base::StringPrintf("Format of the output. " "Accepted values are '%s' and '%s'. When not set, defaults to '%s'.", kOutputFormatProto, kOutputFormatBinary, kOutputFormatBinary), &output_format_); Loading