From 05af549bad09a9b11606c2bda8d2df76d815ca57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kleines=20Filmr=C3=B6llchen?= Date: Wed, 4 Oct 2023 12:33:54 +0200 Subject: [PATCH] pkg: Parse dependencies as part of the main port entry The "dependency" lines really belong to the main port entry, it doesn't make sense logically to represent them separately and handling them together will also allow easier dependency management later on. This commit greatly simplifies the port database parsing to facilitate this, and removes the -d option from the command line. Instead, ports are listed with their dependencies, if they have any. --- Base/usr/share/man/man1/pkg.md | 3 +- Userland/Utilities/pkg/InstalledPort.cpp | 63 ++++++++++++++++-------- Userland/Utilities/pkg/InstalledPort.h | 8 +-- Userland/Utilities/pkg/main.cpp | 26 +++------- 4 files changed, 56 insertions(+), 44 deletions(-) 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.");