diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index b9a68fbdae449..93416222ae5ae 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1612,6 +1612,8 @@ FILE: ../../../flutter/shell/platform/windows/text_input_plugin.cc FILE: ../../../flutter/shell/platform/windows/text_input_plugin.h FILE: ../../../flutter/shell/platform/windows/text_input_plugin_delegate.h FILE: ../../../flutter/shell/platform/windows/text_input_plugin_unittest.cc +FILE: ../../../flutter/shell/platform/windows/uwptool_commands.cc +FILE: ../../../flutter/shell/platform/windows/uwptool_commands.h FILE: ../../../flutter/shell/platform/windows/uwptool_main.cc FILE: ../../../flutter/shell/platform/windows/uwptool_utils.cc FILE: ../../../flutter/shell/platform/windows/uwptool_utils.h diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index 3402ed8434abf..5a8a5d19c54dd 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -316,9 +316,13 @@ source_set("uwptool_utils") { } sources = [ + "uwptool_commands.cc", + "uwptool_commands.h", "uwptool_utils.cc", "uwptool_utils.h", ] + + deps = [ ":string_conversion" ] } # Command-line tool used by the flutter tool that serves a similar purpose to diff --git a/shell/platform/windows/uwptool_commands.cc b/shell/platform/windows/uwptool_commands.cc new file mode 100644 index 0000000000000..8a54ebee247ae --- /dev/null +++ b/shell/platform/windows/uwptool_commands.cc @@ -0,0 +1,112 @@ +#include "flutter/shell/platform/windows/uwptool_commands.h" + +#include +#include + +#include "flutter/shell/platform/windows/string_conversion.h" +#include "flutter/shell/platform/windows/uwptool_utils.h" + +namespace flutter { + +bool ListAppsCommand::ValidateArgs(const std::vector& args) const { + return true; +} + +int ListAppsCommand::Run(const std::vector& args) const { + flutter::ApplicationStore app_store; + for (const flutter::Application& app : app_store.GetApps()) { + std::wcout << app.GetPackageFamily() << std::endl; + } + return 0; +} + +bool InstallCommand::ValidateArgs(const std::vector& args) const { + return args.size() >= 1; +} + +int InstallCommand::Run(const std::vector& args) const { + std::wstring package_uri = flutter::Utf16FromUtf8(args[0]); + std::vector dependency_uris; + for (int i = 1; i < args.size(); ++i) { + dependency_uris.push_back(flutter::Utf16FromUtf8(args[i])); + } + flutter::ApplicationStore app_store; + if (app_store.InstallApp(package_uri, dependency_uris)) { + std::wcerr << L"Installed application " << package_uri << std::endl; + return 0; + } + return 1; +} + +bool UninstallCommand::ValidateArgs( + const std::vector& args) const { + return args.size() >= 1; +} + +int UninstallCommand::Run(const std::vector& args) const { + std::wstring package_family = flutter::Utf16FromUtf8(args[0]); + bool success = true; + flutter::ApplicationStore app_store; + for (flutter::Application& app : app_store.GetApps(package_family)) { + if (app.Uninstall()) { + std::wcerr << L"Uninstalled application " << app.GetPackageFullName() + << std::endl; + } else { + std::wcerr << L"error: Failed to uninstall application " + << app.GetPackageFullName() << std::endl; + success = false; + } + } + return success ? 0 : 1; +} + +bool LaunchCommand::ValidateArgs(const std::vector& args) const { + return args.size() >= 1; +} + +int LaunchCommand::Run(const std::vector& args) const { + // Get the package family name. + std::string package_family = args[0]; + + // Concatenate the remaining args, comma-separated. + std::ostringstream app_args; + for (int i = 1; i < args.size(); ++i) { + app_args << args[i]; + if (i < args.size() - 1) { + app_args << ","; + } + } + int process_id = LaunchApp(flutter::Utf16FromUtf8(package_family), + flutter::Utf16FromUtf8(app_args.str())); + if (process_id == -1) { + std::cerr << "error: Failed to launch app with package family " + << package_family << std::endl; + return 1; + } + + // Write an informative message for the user to stderr. + std::cerr << "Launched app with package family " << package_family + << ". PID: " << std::endl; + // Write the PID to stdout. The flutter tool reads this value in. + std::cout << process_id << std::endl; + return 0; +} + +// Launches the app installed on the system with the specified package. +// +// Returns -1 if no matching app, or multiple matching apps are found, or if +// the app fails to launch. Otherwise, the process ID of the launched app is +// returned. +int LaunchCommand::LaunchApp(const std::wstring_view package_family, + const std::wstring_view args) const { + flutter::ApplicationStore app_store; + for (flutter::Application& app : app_store.GetApps(package_family)) { + int process_id = app.Launch(args); + if (process_id != -1) { + return process_id; + } + } + return -1; +} + +} // namespace flutter diff --git a/shell/platform/windows/uwptool_commands.h b/shell/platform/windows/uwptool_commands.h new file mode 100644 index 0000000000000..2917c63efa411 --- /dev/null +++ b/shell/platform/windows/uwptool_commands.h @@ -0,0 +1,94 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_UWPTOOL_COMMANDS_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_UWPTOOL_COMMANDS_H_ + +#include +#include + +namespace flutter { + +// A uwptool command that can be invoked as the first argument of the uwptool +// arguments list. +class Command { + public: + Command(const std::string_view name, + const std::string_view usage, + const std::string_view description) + : name_(name), usage_(usage), description_(description) {} + virtual ~Command() {} + + std::string GetCommandName() const { return name_; } + std::string GetUsage() const { return usage_; } + std::string GetDescription() const { return description_; } + + // Returns true if the arguments list constitute valid arguments for this + // command. + virtual bool ValidateArgs(const std::vector& args) const = 0; + + // Invokes the command with the specified arguments list. + virtual int Run(const std::vector& args) const = 0; + + private: + std::string name_; + std::string usage_; + std::string description_; +}; + +// Command that prints a list of all installed applications on the system. +class ListAppsCommand : public Command { + public: + ListAppsCommand() + : Command("listapps", + "listapps", + "List installed apps by package family name") {} + + bool ValidateArgs(const std::vector& args) const override; + int Run(const std::vector& args) const override; +}; + +// Command that installs the specified package and dependencies. +class InstallCommand : public Command { + public: + InstallCommand() + : Command("install", + "install PACKAGE_URI DEPENDENCY_URI...", + "Install the specified package with all listed dependencies") {} + + bool ValidateArgs(const std::vector& args) const override; + int Run(const std::vector& args) const override; +}; + +// Command that uninstalls the specified package. +class UninstallCommand : public Command { + public: + UninstallCommand() + : Command("uninstall", + "uninstall PACKAGE_FAMILY_NAME", + "Uninstall the specified package") {} + + bool ValidateArgs(const std::vector& args) const override; + int Run(const std::vector& args) const override; +}; + +// Command that launches the specified application package. +class LaunchCommand : public Command { + public: + LaunchCommand() + : Command("launch", + "launch PACKAGE_FAMILY_NAME", + "Launch the specified package") {} + + bool ValidateArgs(const std::vector& args) const override; + int Run(const std::vector& args) const override; + + private: + int LaunchApp(const std::wstring_view package_family, + const std::wstring_view args) const; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_UWPTOOL_COMMANDS_H_ diff --git a/shell/platform/windows/uwptool_main.cc b/shell/platform/windows/uwptool_main.cc index 0183716b90610..eedc33c79f206 100644 --- a/shell/platform/windows/uwptool_main.cc +++ b/shell/platform/windows/uwptool_main.cc @@ -5,83 +5,33 @@ #include #include -#include +#include #include -#include +#include +#include #include #include #include "flutter/fml/command_line.h" -#include "flutter/shell/platform/windows/string_conversion.h" -#include "flutter/shell/platform/windows/uwptool_utils.h" +#include "flutter/shell/platform/windows/uwptool_commands.h" namespace { -// Prints a list of installed UWP apps to stdout. -void PrintInstalledApps() { - flutter::ApplicationStore app_store; - for (const flutter::Application& app : app_store.GetApps()) { - std::wcout << app.GetPackageFamily() << std::endl; - } -} - -// Launches the app installed on the system with the specified package. -// -// Returns -1 if no matching app, or multiple matching apps are found, or if -// the app fails to launch. Otherwise, the process ID of the launched app is -// returned. -int LaunchApp(const std::wstring_view package_family, - const std::wstring_view args) { - flutter::ApplicationStore app_store; - for (flutter::Application& app : app_store.GetApps(package_family)) { - int process_id = app.Launch(args); - if (process_id != -1) { - return process_id; - } - } - return -1; -} +using CommandMap = std::map>; -// Installs the app in the specified build output directory. -// -// Returns true on success. -bool InstallApp(const std::wstring_view package_uri, - const std::vector& dependency_uris) { - flutter::ApplicationStore app_store; - if (app_store.InstallApp(package_uri, dependency_uris)) { - std::wcerr << L"Installed application " << package_uri << std::endl; - return true; - } - return false; -} - -// Uninstalls the app with the specified package. -// -// Returns true on success. -bool UninstallApp(const std::wstring_view package_family) { - bool success = true; - flutter::ApplicationStore app_store; - for (flutter::Application& app : app_store.GetApps(package_family)) { - if (app.Uninstall()) { - std::wcerr << L"Uninstalled application " << app.GetPackageFullName() - << std::endl; - } else { - std::wcerr << L"error: Failed to uninstall application " - << app.GetPackageFullName() << std::endl; - success = false; - } +// Prints the command usage to stderr. +void PrintUsage(const CommandMap& commands) { + std::cerr << "usage: uwptool COMMAND [ARGUMENTS]" << std::endl; + std::cerr << std::endl; + std::cerr << "Available commands:" << std::endl; + for (const auto& [command_name, command] : commands) { + std::cerr << " " << std::left << std::setw(15) << command_name + << command->GetDescription() << std::endl; } - return success; } -// Prints the command usage to stderr. -void PrintUsage() { - std::cerr << "usage: uwptool COMMAND [ARGUMENTS]" << std::endl - << "commands:" << std::endl - << " listapps list all apps" << std::endl - << " launch PACKAGE_FAMILY launch an app" << std::endl - << " install PACKAGE_URI DEP_URI... install an app" << std::endl - << " uninstall PACKAGE_FAMILY uninstall an app" << std::endl; +void PrintCommandUsage(const flutter::Command& command) { + std::cerr << "usage: uwptool " << command.GetUsage() << std::endl; } } // namespace @@ -89,69 +39,37 @@ void PrintUsage() { int main(int argc, char** argv) { winrt::init_apartment(); + // Register commands alphabetically, to make usage string clearer. + CommandMap commands; + commands.emplace("install", std::make_unique()); + commands.emplace("launch", std::make_unique()); + commands.emplace("listapps", std::make_unique()); + commands.emplace("uninstall", std::make_unique()); + + // Parse command line arguments. auto command_line = fml::CommandLineFromArgcArgv(argc, argv); if (command_line.positional_args().size() < 1) { - PrintUsage(); + PrintUsage(commands); return 1; } - - const std::vector& args = command_line.positional_args(); - std::string command = args[0]; - if (command == "listapps") { - PrintInstalledApps(); - return 0; - } else if (command == "launch") { - if (args.size() < 2) { - PrintUsage(); - return 1; - } - - // Get the package family name. - std::string package_family = args[1]; - - // Concatenate the remaining args, comma-separated. - std::ostringstream app_args; - for (int i = 2; i < args.size(); ++i) { - app_args << args[i]; - if (i < args.size() - 1) { - app_args << ","; - } - } - int process_id = LaunchApp(flutter::Utf16FromUtf8(package_family), - flutter::Utf16FromUtf8(app_args.str())); - if (process_id == -1) { - std::cerr << "error: Failed to launch app with package family " - << package_family << std::endl; - return 1; - } - - // Write an informative message for the user to stderr. - std::cerr << "Launched app with package family " << package_family - << ". PID: " << std::endl; - // Write the PID to stdout. The flutter tool reads this value in. - std::cout << process_id << std::endl; - return 0; - } else if (command == "install") { - if (args.size() < 2) { - PrintUsage(); - return 1; - } - std::wstring package_uri = flutter::Utf16FromUtf8(args[1]); - std::vector dependency_uris; - for (int i = 2; i < args.size(); ++i) { - dependency_uris.push_back(flutter::Utf16FromUtf8(args[i])); - } - return InstallApp(package_uri, dependency_uris) ? 0 : 1; - } else if (command == "uninstall") { - if (args.size() < 2) { - PrintUsage(); - return 1; - } - std::string package_family = args[1]; - return UninstallApp(flutter::Utf16FromUtf8(package_family)) ? 0 : 1; + std::vector command_args( + command_line.positional_args().begin() + 1, + command_line.positional_args().end()); + + // Determine the command. + const std::string& command_name = command_line.positional_args()[0]; + const auto& it = commands.find(command_name); + if (it == commands.end()) { + std::cerr << "Unknown command: " << command_name << std::endl; + PrintUsage(commands); + return 1; } - std::cerr << "Unknown command: " << command << std::endl; - PrintUsage(); - return 1; + // Run the command. + auto& command = it->second; + if (!command->ValidateArgs(command_args)) { + PrintCommandUsage(*command); + return 1; + } + return command->Run(command_args); }