1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 08:27:45 +00:00

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.
This commit is contained in:
kleines Filmröllchen 2023-10-04 12:33:54 +02:00 committed by Tim Schumacher
parent a5f566c2c6
commit 05af549bad
4 changed files with 56 additions and 44 deletions

View file

@ -5,7 +5,7 @@ pkg - Package Manager
## Synopsis ## Synopsis
```**sh ```**sh
$ pkg [-l] [-d] [-u] [-v] [-q package] $ pkg [-l] [-u] [-v] [-q package]
``` ```
## Description ## Description
@ -17,7 +17,6 @@ It does not currently support installing and uninstalling packages. To install t
## Options ## Options
* `-l`, `--list-manual-ports`: Show all manually-installed ports * `-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 * `-u`, `--update-ports-database`: Sync/Update ports database
* `-v`, `--verbose`: Verbose output * `-v`, `--verbose`: Verbose output
* `-q`, `--query-package`: Query the ports database for package name * `-q`, `--query-package`: Query the ports database for package name

View file

@ -1,14 +1,25 @@
/* /*
* Copyright (c) 2023, Liav A. <liavalb@hotmail.co.il> * Copyright (c) 2023, Liav A. <liavalb@hotmail.co.il>
* Copyright (c) 2023, kleines Filmröllchen <filmroellchen@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include "InstalledPort.h" #include "InstalledPort.h"
#include <AK/Function.h> #include <AK/Function.h>
#include <AK/StringUtils.h>
#include <LibCore/File.h> #include <LibCore/File.h>
#include <LibCore/System.h> #include <LibCore/System.h>
Optional<InstalledPort::Type> InstalledPort::type_from_string(StringView type)
{
if (type == "auto"sv)
return Type::Auto;
if (type == "manual"sv)
return Type::Manual;
return {};
}
ErrorOr<HashMap<String, InstalledPort>> InstalledPort::read_ports_database() ErrorOr<HashMap<String, InstalledPort>> InstalledPort::read_ports_database()
{ {
auto file = TRY(Core::File::open(ports_database, Core::File::OpenMode::Read)); auto file = TRY(Core::File::open(ports_database, Core::File::OpenMode::Read));
@ -18,27 +29,39 @@ ErrorOr<HashMap<String, InstalledPort>> InstalledPort::read_ports_database()
HashMap<String, InstalledPort> ports; HashMap<String, InstalledPort> ports;
while (TRY(buffered_file->can_read_line())) { while (TRY(buffered_file->can_read_line())) {
auto line = TRY(buffered_file->read_line(buffer)); auto line = TRY(buffered_file->read_line(buffer));
if (line.is_empty()) { if (line.is_empty())
continue; continue;
} else if (line.starts_with("dependency"sv)) {
auto parts = line.split_view(' '); auto parts = line.split_view(' ');
VERIFY(parts.size() == 3); if (parts.size() < 2) {
auto type = InstalledPort::Type::Dependency; dbgln("Invalid database entry {} (only {} parts)", line, parts.size());
// FIXME: Add versioning when printing these ports! // FIXME: Skip over invalid entries instead?
auto name = TRY(String::from_utf8(parts[2])); return Error::from_string_view("Database entry too short"sv);
TRY(ports.try_set(name, InstalledPort { TRY(String::from_utf8(parts[2])), type, {} })); }
} else if (line.starts_with("auto"sv)) { auto string_type = parts[0];
auto parts = line.split_view(' '); auto name = TRY(String::from_utf8(parts[1]));
VERIFY(parts.size() == 3);
auto type = InstalledPort::Type::Auto; if (auto maybe_type = type_from_string(string_type); maybe_type.has_value()) {
auto name = TRY(String::from_utf8(parts[1])); auto const type = maybe_type.release_value();
TRY(ports.try_set(name, InstalledPort { name, type, TRY(String::from_utf8(parts[2])) })); if (parts.size() < 3)
} else if (line.starts_with("manual"sv)) { return Error::from_string_view("Port is missing a version specification"sv);
auto parts = line.split_view(' '); auto version = TRY(String::from_utf8(parts[2]));
VERIFY(parts.size() == 3);
auto type = InstalledPort::Type::Manual; auto& port = ports.ensure(name, [&] { return InstalledPort { name, {}, {} }; });
auto name = TRY(String::from_utf8(parts[1])); port.m_type = type;
TRY(ports.try_set(name, InstalledPort { name, type, TRY(String::from_utf8(parts[2])) })); port.m_version = move(version);
} else if (string_type == "dependency"sv) {
// Accept an empty dependency list.
auto dependency_views = parts.span().slice(2);
Vector<String> 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 { } else {
return Error::from_string_literal("Unknown installed port type"); return Error::from_string_literal("Unknown installed port type");
} }

View file

@ -17,15 +17,15 @@ class InstalledPort {
public: public:
enum class Type { enum class Type {
Auto, Auto,
Dependency,
Manual, Manual,
}; };
static Optional<Type> type_from_string(StringView);
static ErrorOr<HashMap<String, InstalledPort>> read_ports_database(); static ErrorOr<HashMap<String, InstalledPort>> read_ports_database();
static ErrorOr<void> for_each_by_type(HashMap<String, InstalledPort>&, Type type, Function<ErrorOr<void>(InstalledPort const&)> callback); static ErrorOr<void> for_each_by_type(HashMap<String, InstalledPort>&, Type type, Function<ErrorOr<void>(InstalledPort const&)> callback);
InstalledPort(String name, Type type, String version) InstalledPort(String name, Type type, String version)
: m_name(name) : m_name(move(name))
, m_type(type) , m_type(type)
, m_version(move(version)) , m_version(move(version))
{ {
@ -36,8 +36,6 @@ public:
{ {
if (m_type == Type::Auto) if (m_type == Type::Auto)
return "Automatic"sv; return "Automatic"sv;
if (m_type == Type::Dependency)
return "Dependency"sv;
if (m_type == Type::Manual) if (m_type == Type::Manual)
return "Manual"sv; return "Manual"sv;
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
@ -45,9 +43,11 @@ public:
StringView name() const { return m_name.bytes_as_string_view(); } StringView name() const { return m_name.bytes_as_string_view(); }
StringView version() const { return m_version.bytes_as_string_view(); } StringView version() const { return m_version.bytes_as_string_view(); }
ReadonlySpan<String> dependencies() const { return m_dependencies.span(); }
private: private:
String m_name; String m_name;
Type m_type; Type m_type;
String m_version; String m_version;
Vector<String> m_dependencies;
}; };

View file

@ -14,11 +14,13 @@
static void print_port_details(InstalledPort const& port) static void print_port_details(InstalledPort const& port)
{ {
outln("{}, installed as {}, version {}", port.name(), port.type_as_string_view(), port.version()); outln("{}, installed as {}, version {}", port.name(), port.type_as_string_view(), port.version());
}
static void print_port_details_without_version(InstalledPort const& port) if (!port.dependencies().is_empty()) {
{ out(" Dependencies:");
outln("{}, installed as {}", port.name(), port.type_as_string_view()); for (auto const& dependency : port.dependencies())
out(" {}", dependency);
outln();
}
} }
ErrorOr<int> serenity_main(Main::Arguments arguments) ErrorOr<int> serenity_main(Main::Arguments arguments)
@ -34,26 +36,24 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
bool verbose = false; bool verbose = false;
bool show_all_installed_ports = false; bool show_all_installed_ports = false;
bool show_all_dependency_ports = false;
bool update_packages_db = false; bool update_packages_db = false;
StringView query_package {}; StringView query_package {};
Core::ArgsParser args_parser; 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_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(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(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.add_option(verbose, "Verbose", "verbose", 'v');
args_parser.parse(arguments); 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."); outln("pkg: No action to be performed was specified.");
return 0; return 0;
} }
HashMap<String, InstalledPort> installed_ports; HashMap<String, InstalledPort> installed_ports;
HashMap<String, AvailablePort> available_ports; HashMap<String, AvailablePort> 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()) { 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); warnln("pkg: {} isn't accessible, did you install a package in the past?", ports_database);
return 1; return 1;
@ -86,16 +86,6 @@ ErrorOr<int> 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<void> {
// 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_null()) {
if (query_package.is_empty()) { if (query_package.is_empty()) {
outln("pkg: Queried package name is empty."); outln("pkg: Queried package name is empty.");