Libelektra: Bibliothek für Typen

Erstellt am 22. Sept. 2020  ·  26Kommentare  ·  Quelle: ElektraInitiative/libelektra

Wir unterstützen jetzt verschiedene Speicherformate, die eine eingebaute Vorstellung von Typen haben (zB YAML, TOML, JSON). All dies muss mit Elektras Art der Darstellung von Typen umgehen und normalerweise verlassen sie sich auf die eine oder andere Weise auf das type Plugin.

Das ist IMO nicht ideal. Wir sollten stattdessen darüber nachdenken, einen Teil des type Plugins in eine type Bibliothek zu extrahieren. Diese Bibliothek könnte dann von Speicher-Plugins verwendet werden. Ich bin mir nicht sicher, wie diese Bibliothek genau aussehen würde (vielleicht kann @bauhaus93 helfen), aber der Umgang mit Typen in all diesen Plugins von Grund auf scheint unnötiger Aufwand zu sein.

Außerdem sollte das type Plugin IMO nur mit Speicherformaten verwendet werden, die keine integrierten Typen haben. Für Formate, die nur eine Teilmenge von Elektras-Typen unterstützen, sollte das type Plugin teilweise deaktiviert werden. Andernfalls kann die Interaktion zwischen dem type Plugin und dem Speicher-Plugin sehr kompliziert werden. Grundsätzlich würde das type Plugin Benutzern nur erlauben, Typen zu Speicherformaten hinzuzufügen, die sie nicht unterstützen.


HINWEIS: Dieses Problem sollte wahrscheinlich nach 1.0 erledigt werden , es sei denn, toml helfen würde. Fühlen Sie sich frei, es zu schließen und das Problem entsprechend zu markieren.

low priority proposal

Alle 26 Kommentare

Ich denke, es sollte die außergewöhnliche Art sein, Bibliotheken auf der Grundlage von Vorschlägen zu bilden. Es ist viel sinnvoller, gemeinsame Funktionen zwischen Plugins zu extrahieren und daraus eine Bibliothek zu erstellen. Das TOML-Plugin von

Versteh mich nicht falsch, es ist ein guter Beitrag zu @bauhaus93. Und wenn es ein zweites Plugin gibt, das die gleiche Funktionalität benötigt, sollten wir es auf jeden Fall in eine Bibliothek legen. Aber Bibliotheken zu erstellen ist viel aufwendiger als Plugin-spezifischen Code zu haben und der Aufwand sollte nur gemacht werden, wenn es tatsächlich mindestens zwei Kunden gibt.

@bauhaus93 Wenn Sie keinen unmittelbaren Vorteil darin sehen, eine

Wenn es ein zweites Plugin gibt, das die gleiche Funktionalität benötigt, sollten wir es auf jeden Fall in eine Bibliothek legen

Solange der Entwickler des zweiten Plugins weiß, wo er das erste Plugin findet und wie man den Code daraus extrahiert, ohne alles zu zerstören, ist das eine gute Strategie, ja. Dies ist leider oft nicht der Fall. Zumal oft das erste Plugin umfangreich verändert werden muss, damit es eine Bibliothek nutzen kann.

Auch die Bibliothek könnte jemanden dazu ermutigen, ein neues Speicher-Plugin zu schreiben, da ein Teil der Arbeit bereits erledigt ist.

Aber ich habe das als low priority getaggt, genau weil ich wusste, dass es eine Menge Arbeit ist und es wahrscheinlich niemand gibt, der das machen möchte.

Bei Typen bin ich mir bezüglich der Wiederverwendbarkeit nicht sicher, außer vielleicht der Validierung/Konvertierung von nicht-dezimalen Ganzzahlen (binär/oktal/hexadezimal) oder Datumsangaben (TOML verwendet RFC 3339-Datumszeiten).
Unabhängig von Typen sehe ich eine gewisse Wiederverwendbarkeit in der Vorbereitung von zu schreibenden KeySets (z. B. Funktionen, die array Metaschlüssel aktualisieren/hinzufügen, array Metaschlüssel ungültiger Arrays entfernen oder fehlende comment/#X vervollständigen

Sie haben es vielleicht noch nicht bemerkt, aber es kann auch Probleme mit der Normalisierung von booleschen Werten geben, die das Typ-Plugin macht. Dies ist wahrscheinlich der am häufigsten verwendete Code, da die meisten Formate true / false , Elektra jedoch 1 / 0 . Ich denke, yamlcpp musste einen speziellen Code hinzufügen, damit boolesche Werte nicht in ganze Zahlen umgewandelt werden oder umgekehrt (oder etwas in diese Richtung).

Ah ja, vergessen, das TOML-Plugin muss diese Werte auch normalisieren.

Das Problem ist nicht nur, dass Sie die Werte normalisieren müssen. Sie müssen auch genau wissen, was das type Plugin tut, da es vor dem toml Plugin in der kdbSet Phase ausgeführt wird. Ich bin mir nicht sicher, ob wir es jemals implementiert haben, aber Sie sollten auch sicherstellen, dass das type Plugin immer nur 1 / 0 oder true / false in der kdbSet Phase, unabhängig von der vom Benutzer bereitgestellten Konfiguration. Andernfalls müsste toml in der Lage sein, die type Plugin-Konfiguration zu parsen, da der Benutzer benutzerdefinierte True- und False-Werte setzen kann (siehe Testfall unten).

https://github.com/ElektraInitiative/libelektra/blob/4b0e9f8bdd6d890a1a3abaf04c543b9c7d33e984/src/plugins/type/testmod_type.c#L734 -L771

Der interessante Teil ist:

https://github.com/ElektraInitiative/libelektra/blob/4b0e9f8bdd6d890a1a3abaf04c543b9c7d33e984/src/plugins/type/testmod_type.c#L749 -L753

Das type Plugin erhält ein 1 in kdbGet (könnte von toml ), gibt aber ein t in kdbSet . Dies könnte so weit gehen, dass ein Benutzer true = 0 und false = 1 was das toml Plugin völlig durcheinander bringen würde. (Ich denke, alle Booleschen würden alle kdbSet umdrehen)


Diese äußerst komplexe Interaktion ist der Grund, warum ich denke, dass das type Plugin für Speicherformate geeignet sein sollte, die keine Typen haben, und diejenigen, die solche haben, sollten die Verwendung von type explizit verbieten. Aber um dies zu ermöglichen, brauchen wir eine einfache Möglichkeit, Typen innerhalb von Speicher-Plugins zu unterstützen, zB eine Typbibliothek.

Da das toml Plugin auch hexadezimale Zahlen verarbeitet, sollte es wahrscheinlich auch explizit die Verwendung des hexnumber Plugins verbieten. (obwohl in diesem Fall meiner Meinung nach weniger Potenzial für Probleme besteht)

Auch die Bibliothek könnte jemanden dazu ermutigen, ein neues Speicher-Plugin zu schreiben, da ein Teil der Arbeit bereits erledigt ist.

Die meisten Benutzer möchten wahrscheinlich nur die Grammatik schreiben und der Rest sollte wie von selbst passieren. Ich frage mich, inwieweit das TOML-Plugin von @bauhaus93 dieses Ziel tatsächlich erreicht hat. Wäre interessant, ein Nicht-TOML-Plugin mit der Codebasis des TOML-Plugins zu erstellen. Eine Typbibliothek allein scheint mir jedoch viel zu spezialisiert, um für die große Aufgabe "ein Speicher-Plugin schreiben" zu nützlich zu sein.

Bei Typen bin ich mir bezüglich der Wiederverwendbarkeit nicht sicher, außer vielleicht der Validierung/Konvertierung von nicht-dezimalen Ganzzahlen (binär/oktal/hexadezimal) oder Datumsangaben (TOML verwendet RFC 3339-Datumszeiten).

Datum/Uhrzeit existierten in Elektra nur zur Validierung, aber dort wurde nur RFC2822 unterstützt. Das Datums-Plugin könnte Ihren Parser wiederverwenden, um RFC 3339 zu validieren, aber ich würde dies als sehr niedrige Priorität einstufen.

Etwas spannender wäre etwas wie keyGetDateTime(Key *k, struct tm *tm) aus einem Schlüssel mit einem (TOML-)Datum.

Unabhängig von Typen sehe ich eine gewisse Wiederverwendbarkeit in der Vorbereitung von zu schreibenden KeySets (zB Funktionen, die Array-Metaschlüssel aktualisieren/hinzufügen, Array-Metaschlüssel ungültiger Arrays entfernen oder fehlende Kommentar-/#X-Metaschlüsseldaten vervollständigen).

Ja, das könnte interessant sein. Aber noch faszinierender wäre die Möglichkeit, die Grammatik und den Touch-Code so wenig wie möglich direkt zu ändern :wink:

Sie haben es vielleicht noch nicht bemerkt, aber es kann auch Probleme mit der Normalisierung von booleschen Werten geben, die das Typ-Plugin macht.

Was fehlt, ist eine Anleitung/Erklärung in doc/tutorials/storage-plugins.md, die einen aktuellen Überblick darüber gibt, auf welche Plugins sich ein Speicher-Plugin eigentlich verlassen sollte. #2330 zeigt an, ob "binär" benötigt wird und dennoch als Standardspeicher geeignet ist.

Sie müssen auch genau wissen, was das type-Plugin tut, da es in der kdbSet-Phase vor dem toml-Plugin ausgeführt wird.

Wahrscheinlich sollten Speicher-Plugins aufhören, das Typ-Plugin zu verwenden und ihre Normalisierung einfach selbst durchführen (von allem, was in ihrem Format wahr/falsch ist, zu 1/0 in Elektra und so weiter). @bauhaus93 welche anderen Funktionen des Typ-Plugins verwenden Sie?

Dies könnte so weit gehen, dass ein Benutzer true = 0 und false = 1 definiert, was das Toml-Plugin völlig durcheinander bringen würde.

Ich wäre dafür, die Funktionalität des Typ-Plugins zu reduzieren. Wenn überhaupt, sollten einige zusätzliche Wahr/Falsch-Werte vom Benutzer definierbar sein (die vorher offensichtlich keine Wahr/Falsch-Werte waren).

Da das toml-Plugin auch hexadezimale Zahlen verarbeitet, sollte es wahrscheinlich auch explizit die Verwendung des hexnumber-Plugins verbieten. (obwohl in diesem Fall meiner Meinung nach weniger Potenzial für Probleme besteht)

Es gibt keine Möglichkeit auszudrücken, dass Plugins nicht zusammenarbeiten (eine solche Funktionalität würde die Montage viel komplizierter machen. Es wäre auch zu viel Arbeit für uns, eine Tabelle zu führen, welches Plugin mit welchem ​​Plugin zusammenarbeitet.). Aber wahrscheinlich wird niemand auf die Idee kommen, sie zusammen zu verwenden, da das TOML-Plugin diese Funktionalität und mehr (zB auch Binärzahlen) bereits bietet.

Die meisten Benutzer möchten wahrscheinlich nur die Grammatik schreiben und der Rest sollte wie von selbst passieren.

Das scheint ein bisschen zu magisch, um möglich zu sein. Dies ist möglicherweise mit einem benutzerdefinierten Codegenerator möglich, der auf einer modifizierten Yacc- oder ANTLR-Grammatik basiert. Aber ich glaube nicht, dass es eine Möglichkeit gibt, Code zu haben, der KeySet s einfach aus einer Grammatik für sehr unterschiedliche Formate wie JSON, XML, TOML und edn erstellt . Wie @'sanssecours festgestellt hat, gibt es auch Formate wie YAML, die sehr schwer in einem Standardgrammatikformat auszudrücken sind.

Eine Typbibliothek allein scheint mir jedoch viel zu spezialisiert, um für die große Aufgabe "ein Speicher-Plugin schreiben" zu nützlich zu sein.

Wir könnten die Bibliothek natürlich zu einer allgemeinen storage Bibliothek erweitern, die weitere Hilfsfunktionen für Speicher-Plugins bereitstellt (zB Umgang mit stdin / stdout und Pipes für den Import/Export). Das Typzeug wäre dann ein Teil davon.

Ich glaube auch, dass Sie unterschätzen, wie kompliziert die Typensachen sein können. Wenn wir eine Standard-Typbibliothek hätten, wäre es auch einfacher, das Typsystem zu erweitern, zB um zusätzlich vorgeparste Binärversionen von ganzen Zahlen zu speichern (zu den String-Versionen, um den Aufwand für das Parsing zu reduzieren). Eine storage Bibliothek könnte auch interne APIs verwenden (falls erforderlich), da sie von den Elektra-Entwicklern gepflegt wird.

Eine andere Standardtypbibliothek würde auch Standardfehlermeldungen für Typprobleme garantieren. Es wäre also sogar für Endverbraucher von Vorteil.

Etwas spannender wäre etwas wie keyGetDateTime(Key *k, struct tm *tm)

Klingt nach einem Job für den Konvertierungsteil von libease (als elektraKeyToDateTime (const Key * key, struct tm * dateTime) ).

@bauhaus93 die Funktionen dort könnten auch für toml nützlich sein. Sie sind so konzipiert, dass zB elektraKeyToFloat und elektraFloatToString perfekt und verlustfrei umlaufen (egal ob man mit einem Float eines Strings beginnt) und sie werden auch in der Highlevel API verwendet. Wenn also toml den Schlüssel mit elektra*ToString , kann er definitiv von der Highlevel-API richtig gelesen werden und toml kann definitiv alles richtig lesen, was die highlevel API mit produziert hat elektraKeyTo* .

eine aktuelle Ansicht, auf welche Plugins ein Speicher-Plugin eigentlich angewiesen sein sollte.

IMO, ein Speicher-Plugin sollte sich niemals auf ein anderes Plugin _verlassen_. Speicher-Plugins können durch andere Plugins erweitert werden, sollten jedoch idealerweise eigenständig funktionieren.

Auch der Umgang mit Binärschlüsseln wäre durch eine Speicher-/Typbibliothek besser gelöst. Auch hier garantiert es einen grundlegenden Standard für Fehlermeldungen usw. Es vermeidet auch die Verwendung des binary Plugins für Formate, die es nicht benötigen. Während binary Kombination mit zB quickdump funktionieren würde, ist es sowohl für die Geschwindigkeit als auch für die Speichergröße schlecht.

Wahrscheinlich sollten Speicher-Plugins das Typ-Plugin nicht mehr verwenden und ihre Normalisierung einfach selbst durchführen

Deshalb habe ich eine Bibliothek vorgeschlagen. Es ist viel besser, eine Bibliothek bereitzustellen, die die Arbeit erledigt, als nur eine informelle Beschreibung (oder sogar eine formale Spezifikation) der Aufgabe des Plugins zu geben. Vor allem, wenn sich die Spezifikation im Laufe der Zeit ändern kann.

Ich wäre dafür, die Funktionalität des Typ-Plugins zu reduzieren.

Warum bereits implementierte Funktionalität wegnehmen? Ursprünglich war die Idee, ein separates boolean Plugin zu haben, aber das verursachte auch Probleme wegen der Plugin-Reihenfolge und dergleichen.

Wenn überhaupt, sollten einige zusätzliche Wahr/Falsch-Werte vom Benutzer definierbar sein (die vorher offensichtlich keine Wahr/Falsch-Werte waren).

Das ist wirklich nicht nötig. Es gibt nur ein Problem, wenn mehr als ein Plugin definiert, was ein boolescher Wert ist.

Sogar true = 0 und false = 1 sind völlig in Ordnung. Elektra selbst bestraft boolesche Werte als " 1 ist der einzige wahre Wert und 0 ist der einzige falsche Wert".

Es gibt keine Möglichkeit auszudrücken, dass Plugins nicht zusammenarbeiten (eine solche Funktionalität würde die Montage viel komplizierter machen. Es wäre auch zu viel Arbeit für uns, eine Tabelle zu führen, welches Plugin mit welchem ​​Plugin zusammenarbeitet.).

Ich bin nicht einverstanden. Eine vollständige Liste wäre natürlich unmöglich (es gibt ja auch 3rd Party Plugins), aber die Lösung ist einfach. Lassen Sie die Plugins die Prüfung selbst durchführen. Entweder in elektra<Plugin>Get oder in einer anderen Funktion, die während kdb mount aufgerufen wird.

Neben Boolean setzt das TOML-Plugin beim Lesen auch die Typen string, double und (unsigned_)long_long.

Ich stimme @kodebach zu , dass das type Plugin aufgrund von Interaktionsschwierigkeiten nur von Plugins ohne eingebautes Typsystem verwendet werden sollte.
Z.B. das TOML-Plugin setzt den type Metaschlüssel für ganze Zahlen beim Lesen auch auf nicht-dezimale Werte (während es in dezimal konvertiert wird, speichert die nicht-dezimale Darstellung in origvalue ). Wenn Sie jedoch einen solchen eingegebenen Wert mit kdb set ändern möchten (und dies mit dem Binär-/Oktal-/Hex-Wert tun), können Sie dies nicht direkt tun (indem Sie den Schlüsselwert setzen), da die type Überprüfungen des Plugin-Typs wären nicht erfolgreich. Sie müssten stattdessen den Metaschlüssel origvalue ändern. (Das Löschen des Metaschlüssels type vor dem Festlegen eines neuen Werts würde nicht funktionieren, da der Metaschlüssel beim Lesen zurückgesetzt wird.)

Das Problem ist nicht nur, dass Sie die Werte normalisieren müssen. Sie müssen auch genau wissen, was das type-Plugin tut, da es in der kdbSet-Phase vor dem toml-Plugin ausgeführt wird. Ich bin mir nicht sicher, ob wir es jemals implementiert haben, aber Sie sollten auch sicherstellen, dass das Typ-Plugin in der kdbSet-Phase immer nur 1/0 oder wahr/falsch produziert, unabhängig von der vom Benutzer bereitgestellten Konfiguration. Andernfalls müsste toml in der Lage sein, die Typ-Plugin-Konfiguration zu parsen, da der Benutzer benutzerdefinierte True- und False-Werte setzen kann (siehe Testfall unten).

Ja, ich habe mich schon gefragt, ob/wie ich tatsächlich nach benutzerdefinierten booleschen Werten suchen kann. Derzeit betrachtet das TOML-Plugin beim Schreiben nur die Werte "1" und "true" als wahr, der Rest würde als falsch angesehen werden.

@kodebach schrieb:

Das scheint ein bisschen zu magisch, um möglich zu sein.

Mit Augeas ist es möglich (aber die Bäume, die Sie bekommen, sind nicht so wünschenswert). Es wäre interessant, wie weit wir mit der aktuellen TOML-Lösung noch entfernt sind. Natürlich müssen Sie etwas Emitter-Code schreiben, aber das ist normalerweise nicht so dramatisch.

JSON, XML

Der Vorteil von Elektra liegt darin, dass so unterschiedlichste Formate in unterschiedlichen Technologien umgesetzt werden können. Der Versuch, XML von Grund auf neu zu implementieren, ist wahrscheinlich nicht die beste Idee. Wenn INI-ähnliche Formate abgedeckt werden könnten, wäre das schon erstaunlich.

Aber natürlich ist das erste und wichtigste, ein gutes TOML-Plugin zu bekommen :1st_place_medal:

Eine andere Standardtypbibliothek würde auch Standardfehlermeldungen für Typprobleme garantieren.

Die Überprüfung kann problemlos in anderen Plugins durchgeführt werden (sobald die #2963 fertig ist). Wenn ein Plugin nur mit einer schönen Fehlermeldung überprüft und fehlschlägt, gibt es wenig/keine Interaktionen.

Klingt nach einem Job für den Konvertierungsteil von libease

Ja, wahrscheinlich könnten einige der Sachen von TOML an libease oder libmeta gehen.

IMO, ein Speicher-Plugin sollte sich niemals auf ein anderes Plugin verlassen.

Bei Binär bin ich mir noch nicht sicher (da es wahrscheinlich etwas ist, das für Standard-Backends nicht benötigt wird), bei allen anderen Funktionen ist dies auch meine Schlussfolgerung. Allerdings ist diese Schlussfolgerung noch nicht allgemein akzeptiert (@sanssecours?) oder dokumentiert.

Deshalb habe ich eine Bibliothek vorgeschlagen. Es ist viel besser, eine Bibliothek bereitzustellen, die die Arbeit erledigt, als nur eine informelle Beschreibung (oder sogar eine formale Spezifikation) der Aufgabe des Plugins zu geben. Vor allem, wenn sich die Spezifikation im Laufe der Zeit ändern kann.

Es kommt darauf an: Wenn es eine große Anzahl gültiger Möglichkeiten gibt, ist ein Tutorial/eine Beschreibung möglicherweise besser als eine komplizierte Bibliothek, die irgendwie versucht, diese Flexibilität zu geben. Und für Serialisierungen gibt es eine immense Bandbreite an validen Möglichkeiten und viele davon haben triviale Implementierungen (zB einfach elektraFormat mit einigen Parametern aufrufen) bis hin zu komplizierten Implementierungen (zB wenn sie viele Convenience-Repräsentationen unterstützen).

Warum bereits implementierte Funktionalität wegnehmen?

Elektra bricht derzeit mit dem Gewicht zusammen, zu viel Code zu pflegen. Jede nutzlose (das heißt, niemand benutzt sie) Codezeile, die wir loswerden, macht Elektra besser.

Leider verursacht auch Code, der in Plugins getrennt ist, Probleme: z. B. auf dem Build-Server oder sobald ein Benutzer versucht, ihn zu verwenden, gibt es unerwünschte Interaktionen/fehlende Doku/...

Wir können nicht alles, was wir derzeit haben, als 1.0 veröffentlichen, Elektra wäre dann eine Enttäuschung. Wir müssen alles loswerden, was nicht gebraucht wird. Wir schätzen jede Reinigung, die Sie tun können.

Das ist auch der Grund, warum TOML INI ersetzen wird. #3491

Lassen Sie die Plugins die Prüfung selbst durchführen.

Das war selten eine gute Lösung. Es wird sehr inkonsistent und die Reihenfolge des Hinzufügens von Plugins kann zu unterschiedlichen Ergebnissen führen. Gibt es einen solchen Code schon irgendwo?

@bauhaus93 schrieb:

Neben Boolean setzt das TOML-Plugin beim Lesen auch die Typen string, double und (unsigned_)long_long.

Aber das alles macht es von selbst ohne das Typ-Plugin? Wofür wird das Typ-Plugin verwendet?

Sie müssten stattdessen den Origvalue-Metaschlüssel ändern.

Ja, hier haben wir noch keine schöne Lösung (#3056). keySetString entfernt origvalue, aber irgendwie ist das Verhalten immer noch nicht so, wie es ein Benutzer erwarten würde.

Derzeit betrachtet das TOML-Plugin beim Schreiben nur die Werte "1" und "true" als wahr, der Rest würde als falsch angesehen werden.

Wahrscheinlich sollten wir strenger sein und bei allem scheitern, nicht bei "0" oder "1". In der TOML-Datei selbst lässt man auch nur "true" und "false" zu und sonst nichts?

Aber das alles macht es von selbst ohne das Typ-Plugin? Wofür wird das Typ-Plugin verwendet?

Ja, es tut es von selbst, die verschiedenen Typen werden während des Lexings abgeglichen. Es wird jedoch nicht überprüft, ob die Dezimal-/Doppelwerte long_long / double über-/unterlaufen, also denke ich, dass dies vom type Plugin erledigt wird.

Wahrscheinlich sollten wir strenger sein und bei allem scheitern, nicht bei "0" oder "1". In der TOML-Datei selbst lässt man auch nur "true" und "false" zu und sonst nichts?

Ja, ich kann das strenger machen. In der Datei selbst wird nur true oder false als Boolean geschrieben/gelesen.

für alle anderen Funktionen ist dies auch mein Fazit.

In diesem Fall brauchen wir eine type Bibliothek. Andernfalls hätte jedes Speicher-Plugin für ein Format mit Typen das Typzeug neu implementiert (da es nicht in Frage kommt, sich auf ein anderes Plugin zu verlassen).

wenn es viele gültige Möglichkeiten gibt, ist ein Tutorial/eine Beschreibung vielleicht besser

Aber auch dann ist ein separates Plugin keine Lösung, denn dann gibt es auch eine Vielzahl möglicher Interaktionen, die in beiden Plugins berücksichtigt werden müssen.

Gibt es einen solchen Code schon irgendwo?

AFAIK tut es nicht. Ich bin mir nicht einmal sicher, ob ein Plugin erkennen könnte, welche anderen Plugins gemountet sind.

Aber das alles macht es von selbst ohne das Typ-Plugin? Wofür wird das Typ-Plugin verwendet?

Ja, es tut es von selbst, die verschiedenen Typen werden während des Lexings abgeglichen. Es wird jedoch nicht überprüft, ob die Dezimal-/Doppelwerte long_long / double über-/unterlaufen, also denke ich, dass dies vom type Plugin erledigt wird.

Ja, type auch Bereichsüberprüfungen durch, validiert float / double und einige andere Dinge wie enum s.

Wahrscheinlich sollten wir strenger sein und bei allem scheitern, nicht bei "0" oder "1". In der TOML-Datei selbst lässt man auch nur "true" und "false" zu und sonst nichts?

Und das ist genau einer dieser enorm komplexen und komplizierten Fälle für Typen oder genauer gesagt Konvertierung/Normalisierung.

Nehmen wir an, toml akzeptiert nur true / false als Eingabe und erzeugt nur 0 / 1 in kdbGet und es akzeptiert nur 0 / 1 und produziert nur true / false in kdbSet . Das würde sowohl der Elektra-Spezifikation als auch der TOML-Spezifikation für boolesche Werte entsprechen. Aber ein Benutzer würde wahrscheinlich erwarten, dass kdb set /some/key/mounted/with/toml true funktionieren würde. Allerdings nicht. Mit der richtigen Konfiguration für type könnte es funktionieren, aber es wird schnell umständlich. Was wäre beispielsweise, wenn der Schlüssel schon einmal vorhanden war. Dann gibt es keinen type Metakey und das type Plugin ignoriert ihn einfach, toml erhält true und beschwert sich, dass true nicht gültig ist boolesch...

Dies zeigt nur, dass ein Speicher-Plugin in der Lage sein muss, alle Typen zu verarbeiten, die das Speicherformat unterstützt, und die damit verbundenen Konvertierungen OHNE andere Plugins zu verwenden.

Elektra bricht derzeit mit dem Gewicht zusammen, zu viel Code zu pflegen. Jede nutzlose (das heißt, niemand benutzt sie) Codezeile, die wir loswerden, macht Elektra besser.

Das ist ein fairer Punkt, obwohl ich nicht denke, dass das einfache Löschen von Code die richtige Lösung ist. Zumindest nicht, wenn es um Plugins geht. Im Kern stimme ich zu, je weniger LOC, desto besser. Bei Plugins können wir leicht sagen, dass das Plugin oder ein Teil davon experimentell ist.

IMO, ein Speicher-Plugin sollte sich niemals auf ein anderes Plugin verlassen.

Allerdings ist diese Schlussfolgerung noch nicht allgemein akzeptiert (@sanssecours?) oder dokumentiert.

Soweit mir bekannt ist, gibt es in der Dokumentation keine Stelle, die besagt, dass ein Speicher-Plugin nicht auf andere Plugins angewiesen sein sollte. Das finde ich auch aus Sicht der Trennung der Belange nicht so toll. Ein gutes Speicher-Plugin zu schreiben ist meiner Meinung nach schon ziemlich viel Arbeit. Die Anforderung, dass ein Speicher-Plugin die Typkonvertierung, Verzeichnisschlüssel und Binärdaten (Base64-Kodierung) übernimmt, macht diese Aufgabe nicht einfacher.

Das finde ich auch aus Sicht der Trennung der Belange nicht so toll. Ein gutes Speicher-Plugin zu schreiben ist meiner Meinung nach schon ziemlich viel Arbeit.

Das ist der Sinn der Helferbibliothek. Es spaltet den gemeinsamen Code auf und bietet dadurch (einige) Trennung von Bedenken sowie eine einfachere Entwicklung des Plugins.

Zu @markus2330s Bedenken, dass die Entwicklung einer Allzweckbibliothek schwieriger ist als ein ähnliches Plugin: Das ist faktisch falsch, denn man könnte einfach die leicht modifizierte Version der aktuellen elektraTypeGet Funktion als Bibliothek bereitstellen. Die Änderungen sind nur erforderlich, weil wir das Plugin * handle durch ein KeySet * config ersetzen müssen. Obwohl dies möglicherweise nicht alle Probleme löst, lässt es das Speicher-Plugin zumindest genau steuern, wie und wann die Typsachen erledigt werden.

Als Beispiel könnte toml einen INI-Fallback-Modus haben, in dem es nicht das TOML-Typsystem verwendet, sondern stattdessen auf type und einen normalen TOML-Modus verschoben wird, in dem es elektraTypeGet bereitstellt mit einer sehr präzisen Konfiguration, die sicherstellt, dass alles der TOML-Spezifikation entspricht.

Kurz gesagt, eine Bibliothek ist aus der Sicht des Speicher-Plugins einfach viel flexibler als ein Plugin. Zumindest mit den aktuellen Plugin-Konfigurationsmöglichkeiten.

Die Anforderung, dass ein Speicher-Plugin die Typkonvertierung, Verzeichnisschlüssel und Binärdaten (Base64-Kodierung) übernimmt, macht diese Aufgabe nicht einfacher.

Lassen Sie uns das aufschlüsseln:

  • Binäre Daten: Es ist nicht wirklich aufwendig, so etwas zu tun:
    if (keyIsBinary (key)) { writeValue (elektraBase64Encode (keyValue (key), keyGetValueSize (key))); } else { writeValue (keyString (value)); }
    Ein separates Plugin würde auch funktionieren, solange das Speicher-Plugin erzwingen kann, dass das andere Plugin unter allen Umständen gemountet ist und einfach davon ausgehen kann, dass es keine Binärschlüssel gibt. Wenn das Plugin immer noch keyIsBinary aufrufen und einen Fehler ausgeben muss, bringt diese Lösung keinen Nutzen. Mir gefällt auch nicht, dass ein separates Binär-Plugin die ganzen KeySet auf einmal konvertieren muss, weil dann alle Base64-Schlüssel ziemlich viel Speicher verschwenden.
  • Verzeichnisschlüssel: Erstens sind diese Nicht-Blatt-Schlüssel mit Werten unter fast allen Umständen seltsam und wir sollten eigentlich empfehlen, sie zu vermeiden. Wenn es um den Umgang mit diesen Schlüsseln geht, denke ich, dass eine Bibliothek, wie in #3256 beschrieben, für diesen Fall viel besser geeignet ist. Es gibt viele Gründe, einschließlich Speicher- und Verarbeitungsaufwand, die Mountpoint-Konfigurationen und Flexibilität unnötig komplizieren. Es scheint, dass @markus2330 (etwas) mit mir in diesem Punkt übereinstimmt.
  • Typen: Jedes Speicher-Plugin für ein Format, das ein natives Typsystem hat, muss zumindest etwas Arbeit für Typen leisten. Dies kann von der vollständigen Konvertierung von Grund auf über den Aufruf einer Bibliothek bis hin zur Konfiguration eines anderen Plugins reichen. Es wird nie möglich sein, dass alles nur funktioniert. Auch wenn a eine sehr detaillierte formale Spezifikation für Typen haben, so dass keine direkte Konfiguration des Typ-Plugins erforderlich ist, muss das Speicher-Plugin diese Spezifikation auf die eine oder andere Weise implementieren.

Es wird jedoch nicht überprüft, ob die Dezimal-/Doppelwerte über-/unterlaufen long_long/double, also denke ich, dass dies vom Typplugin erledigt wird.

Okay, Sie verwenden es im Grunde nur zur Überprüfung.

Aber auch dann ist ein separates Plugin keine Lösung

Nein, die separaten Plugins sind leider nicht die Lösung. Da sind wir gescheitert. Die aktuelle Lösung besteht darin, dass jedes Speicher-Plugin alles (außer der binären Behandlung) basierend auf doc/tutorials/storage-plugins.md implementiert

Aber ein Benutzer würde wahrscheinlich erwarten, dass kdb set /some/key/mounted/with/toml true funktioniert.

Nein, das sollte ein Benutzer nicht erwarten. In Elektra 1/0 sind wahr/falsch. Nur Speicher-Plugins können dies auf etwas anderes abbilden.

Begründung: Da zumindest auf der Spezifikationsebene nur 1/0 funktionieren, wäre es nur verwirrend, true/false anderswo (mit Ausnahme von Speicher-Plugins) zum Laufen zu bringen.

Dies zeigt nur, dass ein Speicher-Plugin in der Lage sein muss, alle Typen zu verarbeiten, die das Speicherformat unterstützt, und die damit verbundenen Konvertierungen OHNE andere Plugins zu verwenden.

Ja, ich stimme zu.

Das ist ein fairer Punkt, obwohl ich nicht denke, dass das einfache Löschen von Code die richtige Lösung ist.

Natürlich müssen wir den "richtigen" Code löschen: den Code, der Ihre Erwartungen erfüllt, ohne ihn zu erfüllen oder Probleme mit anderen Teilen von Elektra zu verursachen. Und einige Funktionen des Typ-Plugins scheinen zusammen mit anderen Teilen von Elektra Probleme zu machen.

Zumindest nicht, wenn es um Plugins geht. Im Kern stimme ich zu, je weniger LOC, desto besser. Bei Plugins können wir leicht sagen, dass das Plugin oder ein Teil davon experimentell ist.

Leider funktioniert dies (noch*) nicht. Die Leute beurteilen den Status von Plugins nicht richtig, siehe zB kürzlich: #3472, wo das ungepflegte und fehlerbehaftete INI-Plugin und noch schlimmer das entmutigte alte xmltool-Plugin für perfekt funktionieren geglaubt wurde.

  • Es funktioniert vielleicht besser, wenn ich #666 überarbeite und wir während der Montage Warnungen ausgeben.

Die Anforderung, dass ein Speicher-Plugin die Typkonvertierung, Verzeichnisschlüssel und Binärdaten (Base64-Kodierung) übernimmt, macht diese Aufgabe nicht einfacher.

@sanssecours wie handhaben die YAML-Plugins die Typkonvertierung?

Das ist faktisch falsch

Wir werden sehen, wenn es fertig ist :stuck_out_tongue_winking_eye:

Kurz gesagt, eine Bibliothek ist aus der Sicht des Speicher-Plugins einfach viel flexibler als ein Plugin. Zumindest mit den aktuellen Plugin-Konfigurationsmöglichkeiten.

Darüber hat niemand gestritten. Aber Flexibilität hat manchmal einen hohen Preis.

Es ist nicht wirklich anstrengend, so etwas zu tun

base64 ist nicht die einzige Möglichkeit, Binärdaten zu codieren. Für Standards, bei denen base64 erforderlich ist, könnte es hartcodiert sein. ( @sanssecours Ist dies bei YAML der Fall?)

Für TOML heißt es jedoch einfach "Base64 oder eine andere geeignete ASCII- oder UTF-8-Kodierung", sodass andere binäre Plugins verwendet werden könnten. Die aktuelle Lösung hat also Vorteile, da Benutzer nach Bedarf oder Bedarf andere binäre Plugins mounten können.

@bauhaus93 - infos/needs = base64 sollte in - infos/needs = binary geändert werden.

Erstens sind diese Nicht-Blatt-Schlüssel mit Werten unter fast allen Umständen seltsam und wir sollten eigentlich empfehlen, sie zu vermeiden.

Sie sind in vielen Formaten sehr verbreitet. Und sie können sehr nützlich sein, wenn Sie eine Spezifikation erweitern (Unterschlüssel aus Schlüsseln mit Werten erstellen).

[Verzeichnisschlüssel] @markus2330 scheint mir in diesem Punkt (etwas)

Ich stimme zu, dass Speicher-Plugins damit umgehen müssen (vielleicht mit einer Bibliothek, aber nicht mit dem "directoryvalue" -Plugin, da das Escapen nicht funktioniert und das korrekte Escapen eine der Hauptaufgaben eines Speicher-Plugins ist).

Okay, Sie verwenden es im Grunde nur zur Überprüfung.

Ich stimme dem Satz "das toml Plugin verwendet das type Plugin" nicht zu. In der aktuellen Version wird nur type empfohlen.

https://github.com/ElektraInitiative/libelektra/blob/c61e388c4aa950cf84aa2f00fba7cdd34a47640e/src/plugins/toml/README.md#L5 -L6

Selbst wenn type als needs deklariert wäre, würde ich es nicht "using" nennen. toml hat keine direkte Kontrolle über type . Deshalb habe ich gesagt, dass toml auf type angewiesen ist. Es erwartet, dass type bestimmte Dinge auf eine bestimmte Weise tun, aber ich kann nichts tun, wenn das nicht der Fall ist.

Es funktioniert vielleicht besser, wenn ich #666 überarbeite und wir während der Montage Warnungen ausgeben.

Ich stimme zu. Vielleicht sogar auf jedem kdbGet , es sei denn, ein spezieller Schlüssel "Ich bestätige, dass dieser Mountpoint experimentelle Plugins verwendet" wurde gesetzt.

base64 ist nicht die einzige Möglichkeit, Binärdaten zu codieren.

Das ist eigentlich ein Argument für ein binary Plugin. Obwohl ich immer noch gerne eine Schnittstelle hätte, über die das Plugin jeweils einen einzelnen Schlüssel bearbeiten kann, könnte dies einige Speichereinsparungen und möglicherweise auch Leistungseinsparungen bewirken. (Aber das ist ein anderes Thema)

Sie sind in vielen Formaten sehr verbreitet.

Hast du ein Beispiel?

Und sie können sehr nützlich sein, wenn Sie eine Spezifikation erweitern (Unterschlüssel aus Schlüsseln mit Werten erstellen).

Stimmt, aber in diesem Fall würde ich eine "Entweder-Oder"-Lösung (vom Endbenutzer-POV) empfehlen. Entweder Sie verwenden den alten Schlüssel mit dem Einzelwert oder Sie verwenden die neue Version mit Unterschlüsseln. Andernfalls wird die Konfiguration wahrscheinlich verwirrend sein.

Um es klar zu sagen, ich denke nicht, dass Nicht-Blatt-Schlüssel mit Werten niemals verwendet werden sollten, aber sie sollten wenn möglich vermieden werden und sind selten (wenn überhaupt) die bevorzugte Lösung.

aber nicht mit dem "directoryvalue"-Plugin, da Escape nicht funktioniert

In #3256 schlug ich die Verwendung von Metadaten vor, um Fluchtprobleme zu lösen. Außerdem gibt es meine Ideen von #3223, die das Fluchtproblem lösen würden (für jeden Anwendungsfall nicht nur directoryvalue ) sowie einige andere Dinge. Siehe auch den (sehr formalen) Vorschlag . Ich werde diesem Dokument heute oder morgen einfache englische Erklärungen hinzufügen, da ich diese Änderungen immer noch sehr befürworte.

@sanssecours wie handhaben die YAML-Plugins die Typkonvertierung?

Yan LR und YAML CPP verwenden das type Plugin für boolesche Werte. YAML CPP verwendet auch das base64 Plugin für Binärdaten.

base64 ist nicht die einzige Möglichkeit, Binärdaten zu codieren. Für Standards, bei denen base64 erforderlich ist, könnte es hartcodiert sein. ( @sanssecours Ist dies bei YAML der Fall?)

Ja, meines Wissens verwenden Binärdaten in YAML immer die Base64-Codierung.

[Nicht-Blatt-Schlüssel mit Werten] Haben Sie ein Beispiel?

XML und die meisten INI-Dialekte (da sie key=value zulassen, auch wenn [key] existiert)

Stimmt, aber in diesem Fall würde ich eine "Entweder-Oder"-Lösung (vom Endbenutzer-POV) empfehlen. Entweder Sie verwenden den alten Schlüssel mit dem Einzelwert oder Sie verwenden die neue Version mit Unterschlüsseln. Andernfalls wird die Konfiguration wahrscheinlich verwirrend sein.

Ja, das klingt vernünftig. Sobald Sie wissen, dass etwas ein Abschnitt ist, verschieben Sie den Wert normalerweise irgendwo innerhalb des Abschnitts.

ZB deluser.conf hat BACKUP = 0 und BACKUP_TO = "." . Bei Abschnitten würden die meisten Anwendungen BACKUP_ENABLE anstelle von einfach BACKUP .

Außerdem gibt es meine Ideen von #3223, die das Fluchtproblem lösen würden (für jeden Anwendungsfall nicht nur directoryvalue ) sowie einige andere Dinge.

Ich habe jetzt den Vorschlag in #3223 aktualisiert. Ich hoffe, es ist jetzt leichter zu verstehen (es ist noch sehr lang).

https://github.com/kodebach/libelektra/blob/dcec6e865bba32f6d83c40c2f711c2e70dde6d62/doc/proposals/keynames.md

Die große Frage ist, wer das alles umsetzen wird. Es ist ziemlich weit weg vom Status Quo, dh viel Arbeit (allein die Änderung der Terminologie ist ein riesiger Arbeitsaufwand). Wer es umsetzen möchte, kann mit dem Vorschlag eine PR erstellen und ich kommentiere ihn. Andernfalls sollten wir einen Schritt zurücktreten und über machbare Lösungen in unserer Reichweite nachdenken.

Übrigens. Der erste Teil des Vorschlags ist eigentlich ein wunderbares Tutorial darüber, wie Schlüsselnamen funktionieren. Es wäre toll, dies als Tutorial zu haben. :funkelndes_herz:

Die große Frage ist, wer das alles umsetzen wird.

Das ist immer die Frage...

Es ist ziemlich weit weg vom Status Quo, dh viel Arbeit (allein die Änderung der Terminologie ist ein riesiger Arbeitsaufwand).

Die Änderungen in der Terminologie sind definitiv der größte Teil, insbesondere die Änderung der gesamten Dokumentation. Dies muss jedoch nicht von einer Person durchgeführt werden. Diese Änderungen sind recht einfach, sie sind nur mühsam, sodass jeder helfen kann, auch ohne umfangreiche Kenntnisse über den Code. Meistens geht es nur darum, die gesamte Dokumentation zu lesen und Vorkommen von Dingen wie "Basisname" zu ersetzen.

Wer es umsetzen möchte, kann mit dem Vorschlag eine PR erstellen und ich kommentiere ihn. Andernfalls sollten wir einen Schritt zurücktreten und über machbare Lösungen in unserer Reichweite nachdenken.

Ich werde eine PR starten, aber ob ich in absehbarer Zeit Zeit habe, sie (allein) fertigzustellen, kann ich nicht sagen.
Ich habe bereits eine lokale Filiale, in der alle Anrufe an keyBaseName , keySetBaseName und keyAddBaseName durch keyLastUnescapedPart , keySetLastUnescapedPart / keySetLastLiteralPart und keyAddUnescapedPart / keyAddLiteralPart . Ich habe das mit einem halbautomatischen Regex-Replace erstellt, nachdem ich den ersten Vorschlag geschrieben hatte.

Aber in diesem Zweig sind die neuen Funktionen nur #define s für die alten, also muss die eigentliche Implementierung noch geschrieben werden und dann müssen Tests und wahrscheinlich Speicher-Plugins aktualisiert werden.

Das größte Problem für mich wären die Speicher-Plugins. Ich kann die Updates für den Kern und die Tests implementieren und vielleicht ein Speicher-Plugin. Aber ich würde es vorziehen, wenn ich nicht den Code für alle Speicher-Plugins studieren und alle Feinheiten aller Formate herausfinden müsste.

Übrigens. Der erste Teil des Vorschlags ist eigentlich ein wunderbares Tutorial darüber, wie Schlüsselnamen funktionieren. Es wäre toll, dies als Tutorial zu haben.

Deshalb habe ich es so geschrieben. Mein Plan war, Teile dieses Vorschlags für die Dokumentation in #3447 wiederzuverwenden. Ich kann es nicht 1:1 verwenden, weil ich einige sehr wichtige Teile weggelassen habe (zB kanonisch vs nicht kanonisch).

Ich muss ehrlich sein und Ihnen keine falschen Hoffnungen machen: Wie Sie in LCDproc gesehen haben, kommt es nicht vor, dass andere bei der Erledigung von Aufgaben nach vorne springen, vor allem nicht, wenn sie mühsam sind. Ein PR, der alle Speicher-Plugins außer einem zerstört, ist nicht zusammenführbar. Und Speicher-Plugins profitieren nicht viel von dieser PR, tatsächlich werden sie "schlechter" in dem Sinne, dass sie plötzlich Syntaxfehler in Dateien erzeugen, die sie jetzt analysieren könnten. Dies bedeutet nicht, dass es insgesamt eine schlechte Idee ist. Mit einigen Verfeinerungen ist es vielleicht besser als der Status Quo, aber ich sehe einfach nicht, wie wir eine so große Aufgabe mit so vielen anderen dringenden wichtigen offenen Aufgaben bewältigen können, die wir gerade haben.

Also konzentrieren wir uns bitte auf #3447 (Dokumentation), endlich #2969 fertig zu bekommen, das TOML-Plugin zu verbessern und andere wichtige Themen, die wir für 1.0 brauchen (https://github.com/ElektraInitiative/libelektra/milestone/12 und https:// github.com/ElektraInitiative/libelektra/milestone/14). Sobald dies gut aussieht, können wir sehen, welche anderen Ideen wir verwirklichen können.

Für mich ist das Fazit dieser Diskussion, dass es definitiv Bedarf an Bibliotheken gibt, um das Schreiben von Speicher-Plugins zu erleichtern, da der Plugin-Ansatz nicht funktioniert hat (außer für Binär ist zu sehen). Diese Schlussfolgerung sollte im Tutorial zum Speicher-Plugin stehen.
@bauhaus93 können Sie die Aufgabe übernehmen, das Tutorial zum Speicher-Plugin fortzusetzen? Sie haben jetzt viele Einblicke, die Sie nicht sehen können, wenn Sie sich den Quellcode des Toml-Plugins ansehen.

Ein PR, der alle Speicher-Plugins außer einem zerstört, ist nicht zusammenführbar.

Ich habe nicht erwartet, dass jemand so eine PR zusammenführt... Ich sagte nur, es wäre schön, wenn andere Leute mit Updates für Speicher-Plugins helfen könnten. Idealerweise der ursprüngliche Autor des Plugins. Nach #3491 werden sowieso einige der komplexeren Speicher-Plugins entfernt, sodass die ganze Aufgabe einfacher wird.

Und Speicher-Plugins profitieren nicht viel von dieser PR, tatsächlich werden sie "schlechter" in dem Sinne, dass sie plötzlich Syntaxfehler in Dateien erzeugen, die sie jetzt analysieren könnten.

Dies sollte nicht der Fall sein. Es gibt sogar eine teilweise Erklärung am Ende des Vorschlags . AFAIK sollte es nicht den Fall geben, dass ein Speicher-Plugin eine Datei ablehnen muss , weil sie nicht in ein KeySet .

Die einzige Ausnahme wären Formate, die direkt die Schlüsselnamen von Elektra verwenden (escaped oder unescaped). Diese akzeptieren nach diesem Vorschlag möglicherweise weniger Dateien als zuvor. Da aber die Syntax für diese Dateien immer von der Syntax für Key Names abhing, ist dies durchaus zu erwarten.

Mit einigen Verfeinerungen ist es vielleicht besser als der Status Quo, aber ich sehe einfach nicht, wie wir eine so große Aufgabe mit so vielen anderen dringenden wichtigen offenen Aufgaben bewältigen können, die wir gerade haben.

Ich hätte nie erwartet, dass dieser Vorschlag sofort angenommen wird. Aber ich denke, wir sollten auf jeden Fall erwägen, es vor 1.0 zu implementieren. Sobald 1.0 veröffentlicht ist, wäre der Vorschlag eine große bahnbrechende Änderung. Ich glaube nicht, dass eine Version 2.0 auch 1 oder 2 Jahre nach 1.0 (geschweige denn früher) eine gute Idee wäre, wenn man die Zielgruppe von Elektra bedenkt.

Also konzentrieren wir uns bitte auf #3447 (Dokumentation), endlich #2969 fertig zu bekommen, das TOML-Plugin zu verbessern und andere wichtige Themen, die wir für 1.0 brauchen

Ich bin völlig einverstanden. Aber auch hier sollten wir es immer noch in Betracht ziehen, denn nach der Veröffentlichung von 1.0 wird das Hinzufügen von Breaking Changes für eine ganze Weile sehr schwierig sein.

Für mich ist das Fazit dieser Diskussion, dass definitiv Bibliotheken benötigt werden, um das Schreiben von Speicher-Plugins zu erleichtern

👍

außer binär ist zu sehen

IMO, der Fall von Binärwerten ist ganz anders. Es ist eine 1:1 Schlüsselwertübersetzung, wie viele andere ( rgbcolor , macaddr , ipaddr , etc), also ist ein Plugin hier eigentlich gut geeignet. Eine Verbesserung könnte jedoch, wie gesagt, eine neue Plugin-API sein, die nur jeweils mit einem Schlüssel arbeitet. Aber das kann leicht nach 1.0 hinzugefügt werden, da es keine bahnbrechende Änderung wäre, wenn es richtig gemacht wird.

die meisten -> müssen?

Ja, ich sehe es genauso: Es ist unrealistisch, dass diese Änderung stattfindet, sobald 1.0 herauskommt (der ganze Zweck von 1.0 besteht darin, solche Entscheidungen einzufrieren, damit sich andere darauf verlassen können) und es wäre schön, solche Verbesserungen vorher zu haben . Aber wie gesagt: Wir müssen uns wirklich darauf konzentrieren, die kritischen Dinge zu erledigen und unsere Energie nicht in Nice-to-have-Kämpfen zu verlieren, die wir mit unserer derzeitigen Manpower nicht gewinnen können.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen