[uwptool] Refactor command-handling to a map (#26309)
Extracts each of the commands (listapps, install, uninstall, launch)
into a command class that is registered at startup. This simplifies
adding further commands, and cleans up the code a bit.
This is a refactoring that introduces no changes to existing functionality.
diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
index ed9fa70..57901f1 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.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 3402ed8..5a8a5d1 100644
--- a/shell/platform/windows/BUILD.gn
+++ b/shell/platform/windows/BUILD.gn
@@ -316,9 +316,13 @@
}
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 0000000..8a54ebe
--- /dev/null
+++ b/shell/platform/windows/uwptool_commands.cc
@@ -0,0 +1,112 @@
+#include "flutter/shell/platform/windows/uwptool_commands.h"
+
+#include <iostream>
+#include <sstream>
+
+#include "flutter/shell/platform/windows/string_conversion.h"
+#include "flutter/shell/platform/windows/uwptool_utils.h"
+
+namespace flutter {
+
+bool ListAppsCommand::ValidateArgs(const std::vector<std::string>& args) const {
+ return true;
+}
+
+int ListAppsCommand::Run(const std::vector<std::string>& 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<std::string>& args) const {
+ return args.size() >= 1;
+}
+
+int InstallCommand::Run(const std::vector<std::string>& args) const {
+ std::wstring package_uri = flutter::Utf16FromUtf8(args[0]);
+ std::vector<std::wstring> 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<std::string>& args) const {
+ return args.size() >= 1;
+}
+
+int UninstallCommand::Run(const std::vector<std::string>& 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<std::string>& args) const {
+ return args.size() >= 1;
+}
+
+int LaunchCommand::Run(const std::vector<std::string>& 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 0000000..2917c63
--- /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 <string>
+#include <vector>
+
+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<std::string>& args) const = 0;
+
+ // Invokes the command with the specified arguments list.
+ virtual int Run(const std::vector<std::string>& 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<std::string>& args) const override;
+ int Run(const std::vector<std::string>& 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<std::string>& args) const override;
+ int Run(const std::vector<std::string>& 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<std::string>& args) const override;
+ int Run(const std::vector<std::string>& 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<std::string>& args) const override;
+ int Run(const std::vector<std::string>& 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 0183716..eedc33c 100644
--- a/shell/platform/windows/uwptool_main.cc
+++ b/shell/platform/windows/uwptool_main.cc
@@ -5,83 +5,33 @@
#include <Windows.h>
#include <winrt/base.h>
-#include <algorithm>
+#include <iomanip>
#include <iostream>
-#include <sstream>
+#include <map>
+#include <memory>
#include <string>
#include <vector>
#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;
-}
-
-// Installs the app in the specified build output directory.
-//
-// Returns true on success.
-bool InstallApp(const std::wstring_view package_uri,
- const std::vector<std::wstring>& 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;
- }
- }
- return success;
-}
+using CommandMap = std::map<std::string, std::unique_ptr<flutter::Command>>;
// 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 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;
+ }
+}
+
+void PrintCommandUsage(const flutter::Command& command) {
+ std::cerr << "usage: uwptool " << command.GetUsage() << std::endl;
}
} // namespace
@@ -89,69 +39,37 @@
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<flutter::InstallCommand>());
+ commands.emplace("launch", std::make_unique<flutter::LaunchCommand>());
+ commands.emplace("listapps", std::make_unique<flutter::ListAppsCommand>());
+ commands.emplace("uninstall", std::make_unique<flutter::UninstallCommand>());
+
+ // Parse command line arguments.
auto command_line = fml::CommandLineFromArgcArgv(argc, argv);
if (command_line.positional_args().size() < 1) {
- PrintUsage();
+ PrintUsage(commands);
+ return 1;
+ }
+ std::vector<std::string> 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;
}
- const std::vector<std::string>& 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<std::wstring> 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;
+ // Run the command.
+ auto& command = it->second;
+ if (!command->ValidateArgs(command_args)) {
+ PrintCommandUsage(*command);
+ return 1;
}
-
- std::cerr << "Unknown command: " << command << std::endl;
- PrintUsage();
- return 1;
+ return command->Run(command_args);
}