diff --git a/Base/usr/share/man/man1/pkg.md b/Base/usr/share/man/man1/pkg.md index 3c335b9d69..7a01fe7a70 100644 --- a/Base/usr/share/man/man1/pkg.md +++ b/Base/usr/share/man/man1/pkg.md @@ -5,7 +5,7 @@ pkg - Package Manager ## Synopsis ```**sh -$ pkg [-l] [-d] [-u] [-v] [-q package] +$ pkg [-l] [-u] [-v] [-q package] ``` ## Description @@ -17,7 +17,6 @@ It does not currently support installing and uninstalling packages. To install t ## Options * `-l`, `--list-manual-ports`: Show all manually-installed ports -* `-d`, `--list-dependency-ports`: Show all dependencies' ports * `-u`, `--update-ports-database`: Sync/Update ports database * `-v`, `--verbose`: Verbose output * `-q`, `--query-package`: Query the ports database for package name diff --git a/Userland/Utilities/pkg/InstalledPort.cpp b/Userland/Utilities/pkg/InstalledPort.cpp index 4e51b01b21..8496929eec 100644 --- a/Userland/Utilities/pkg/InstalledPort.cpp +++ b/Userland/Utilities/pkg/InstalledPort.cpp @@ -1,14 +1,25 @@ /* * Copyright (c) 2023, Liav A. + * Copyright (c) 2023, kleines Filmröllchen * * SPDX-License-Identifier: BSD-2-Clause */ #include "InstalledPort.h" #include +#include #include #include +Optional InstalledPort::type_from_string(StringView type) +{ + if (type == "auto"sv) + return Type::Auto; + if (type == "manual"sv) + return Type::Manual; + return {}; +} + ErrorOr> InstalledPort::read_ports_database() { auto file = TRY(Core::File::open(ports_database, Core::File::OpenMode::Read)); @@ -18,27 +29,39 @@ ErrorOr> InstalledPort::read_ports_database() HashMap ports; while (TRY(buffered_file->can_read_line())) { auto line = TRY(buffered_file->read_line(buffer)); - if (line.is_empty()) { + if (line.is_empty()) continue; - } else if (line.starts_with("dependency"sv)) { - auto parts = line.split_view(' '); - VERIFY(parts.size() == 3); - auto type = InstalledPort::Type::Dependency; - // FIXME: Add versioning when printing these ports! - auto name = TRY(String::from_utf8(parts[2])); - TRY(ports.try_set(name, InstalledPort { TRY(String::from_utf8(parts[2])), type, {} })); - } else if (line.starts_with("auto"sv)) { - auto parts = line.split_view(' '); - VERIFY(parts.size() == 3); - auto type = InstalledPort::Type::Auto; - auto name = TRY(String::from_utf8(parts[1])); - TRY(ports.try_set(name, InstalledPort { name, type, TRY(String::from_utf8(parts[2])) })); - } else if (line.starts_with("manual"sv)) { - auto parts = line.split_view(' '); - VERIFY(parts.size() == 3); - auto type = InstalledPort::Type::Manual; - auto name = TRY(String::from_utf8(parts[1])); - TRY(ports.try_set(name, InstalledPort { name, type, TRY(String::from_utf8(parts[2])) })); + + auto parts = line.split_view(' '); + if (parts.size() < 2) { + dbgln("Invalid database entry {} (only {} parts)", line, parts.size()); + // FIXME: Skip over invalid entries instead? + return Error::from_string_view("Database entry too short"sv); + } + auto string_type = parts[0]; + auto name = TRY(String::from_utf8(parts[1])); + + if (auto maybe_type = type_from_string(string_type); maybe_type.has_value()) { + auto const type = maybe_type.release_value(); + if (parts.size() < 3) + return Error::from_string_view("Port is missing a version specification"sv); + auto version = TRY(String::from_utf8(parts[2])); + + auto& port = ports.ensure(name, [&] { return InstalledPort { name, {}, {} }; }); + port.m_type = type; + port.m_version = move(version); + } else if (string_type == "dependency"sv) { + // Accept an empty dependency list. + auto dependency_views = parts.span().slice(2); + Vector dependencies; + TRY(dependencies.try_ensure_capacity(dependency_views.size())); + for (auto const& view : dependency_views) + dependencies.unchecked_append(TRY(String::from_utf8(view))); + + // Assume the port as automatically installed if the "dependency" line occurs before the "manual"/"auto" line. + // This is fine since these entries override the port type in any case. + auto& port = ports.ensure(name, [&] { return InstalledPort { name, Type::Auto, {} }; }); + port.m_dependencies = move(dependencies); } else { return Error::from_string_literal("Unknown installed port type"); } diff --git a/Userland/Utilities/pkg/InstalledPort.h b/Userland/Utilities/pkg/InstalledPort.h index 414c0a504b..d38d89a8fd 100644 --- a/Userland/Utilities/pkg/InstalledPort.h +++ b/Userland/Utilities/pkg/InstalledPort.h @@ -17,15 +17,15 @@ class InstalledPort { public: enum class Type { Auto, - Dependency, Manual, }; + static Optional type_from_string(StringView); static ErrorOr> read_ports_database(); static ErrorOr for_each_by_type(HashMap&, Type type, Function(InstalledPort const&)> callback); InstalledPort(String name, Type type, String version) - : m_name(name) + : m_name(move(name)) , m_type(type) , m_version(move(version)) { @@ -36,8 +36,6 @@ public: { if (m_type == Type::Auto) return "Automatic"sv; - if (m_type == Type::Dependency) - return "Dependency"sv; if (m_type == Type::Manual) return "Manual"sv; VERIFY_NOT_REACHED(); @@ -45,9 +43,11 @@ public: StringView name() const { return m_name.bytes_as_string_view(); } StringView version() const { return m_version.bytes_as_string_view(); } + ReadonlySpan dependencies() const { return m_dependencies.span(); } private: String m_name; Type m_type; String m_version; + Vector m_dependencies; }; diff --git a/Userland/Utilities/pkg/main.cpp b/Userland/Utilities/pkg/main.cpp index 8a4839a985..0079f7c515 100644 --- a/Userland/Utilities/pkg/main.cpp +++ b/Userland/Utilities/pkg/main.cpp @@ -14,11 +14,13 @@ static void print_port_details(InstalledPort const& port) { outln("{}, installed as {}, version {}", port.name(), port.type_as_string_view(), port.version()); -} -static void print_port_details_without_version(InstalledPort const& port) -{ - outln("{}, installed as {}", port.name(), port.type_as_string_view()); + if (!port.dependencies().is_empty()) { + out(" Dependencies:"); + for (auto const& dependency : port.dependencies()) + out(" {}", dependency); + outln(); + } } ErrorOr serenity_main(Main::Arguments arguments) @@ -34,26 +36,24 @@ ErrorOr serenity_main(Main::Arguments arguments) bool verbose = false; bool show_all_installed_ports = false; - bool show_all_dependency_ports = false; bool update_packages_db = false; StringView query_package {}; Core::ArgsParser args_parser; args_parser.add_option(show_all_installed_ports, "Show all manually-installed ports", "list-manual-ports", 'l'); - args_parser.add_option(show_all_dependency_ports, "Show all dependencies' ports", "list-dependency-ports", 'd'); args_parser.add_option(update_packages_db, "Sync/Update ports database", "update-ports-database", 'u'); args_parser.add_option(query_package, "Query ports database for package name", "query-package", 'q', "Package name to query"); args_parser.add_option(verbose, "Verbose", "verbose", 'v'); args_parser.parse(arguments); - if (!update_packages_db && !show_all_installed_ports && !show_all_dependency_ports && query_package.is_null()) { + if (!update_packages_db && !show_all_installed_ports && query_package.is_null()) { outln("pkg: No action to be performed was specified."); return 0; } HashMap installed_ports; HashMap available_ports; - if (show_all_installed_ports || show_all_dependency_ports || !query_package.is_null()) { + if (show_all_installed_ports || !query_package.is_null()) { if (Core::System::access(ports_database, R_OK).is_error()) { warnln("pkg: {} isn't accessible, did you install a package in the past?", ports_database); return 1; @@ -86,16 +86,6 @@ ErrorOr serenity_main(Main::Arguments arguments) })); } - if (show_all_dependency_ports) { - outln("Dependencies-installed ports:"); - TRY(InstalledPort::for_each_by_type(installed_ports, InstalledPort::Type::Dependency, [](auto& port) -> ErrorOr { - // NOTE: Dependency entries don't specify versions, so we don't - // try to print it. - print_port_details_without_version(port); - return {}; - })); - } - if (!query_package.is_null()) { if (query_package.is_empty()) { outln("pkg: Queried package name is empty.");