Das Ruby setup Paket

Wie man eigene Module und Anwendungen installiert

Winfried Mueller, www.reintechnisch.de, Start: 06.04.2004, Stand: 02.03.2005

1. Einführung

Wie schön wäre die Welt, wenn jedes Programmpaket sich auf gleiche Weise installieren ließe. Man bräuchte sich nicht immer wieder einlesen, wie man denn nun ein Programm oder Module auf die Platte bringt.

Für die Programmiersprache Ruby hat uns Minero Aoki das wunderbare Paket setup geschrieben. Es ist flexibel und offen gestaltet, es dürfte alle Anforderungen an Installation abdecken. Durch den Einsatz von setup können Programme für den Anwender nun immer auf die gleiche Art installiert werden. Hierzu reicht der 3-Satz:

 
# ruby setup.rb config
# ruby setup.rb setup
# ruby setup.rb install

Als ich anfing, mich mit setup.rb zu beschäftigen, spielte ich schon mit dem Gedanken, lieber was eigenes zu schreiben. Mir kam das System irgendwie zu kompliziert vor. Zum Glück nahm ich mir doch die Zeit, es zu verstehen. Dabei merkte ich, wie verblüffend einfach die Anwendung ist. Weil mir die Dokumentation etwas dünn erscheint, schreibe ich diesen Artikel.

Ich tue dies in der Hoffnung, dass sich damit der Einsatz von setup.rb weit verbreitet und wir endlich einen einheitlichen Installationsprozess haben.

Die Beschreibung orientiert sich an der Linux-Plattform, ist aber größtenteils auch für andere Plattformen übertragbar.

2. Ganz einfach: Setup für eigene Module erstellen

Die Anwendung von setup.rb ist wirklich simpel. Um dies zu demonstrieren, gehen wir von einem einfachen Beispiel aus. Wir haben ein kleines Modul Namens saphir.rb geschrieben, welches wir nun im site-ruby Verzeichnis installiert haben wollen. Und zwar in einem Unterverzeichnis namens myClasses. Später wollen wir es mittels require "myClasses/saphir" in unsere Skripte einbinden können.

Unser Projekt bekommt ein eigenes Verzeichnis, in dem wir einige Unterverzeichnisse anlegen. Ins Hauptverzeichnis legen wir die setup.rb, wie wir sie im Paket setup vorfinden. Unser Skript legen wir in ./lib/myClasses ab:

 
saphir
  /lib
    /myClasses
      saphir.rb
  setup.rb

Das war schon alles! Mehr braucht es nicht.

Wenn man jetzt im Verzeichnis saphir ist, kann man zuerst einmal ruby setup.rb config aufrufen.

Daraufhin checkt das System die aktuelle Umgebung, erkennt automatisch die entsprechenden Installationspfade und erzeugt daraufhin die config.save. In dieser Datei wird die Konfiguration abgespeichert. Sie kann bei Bedarf noch von Hand angepasst werden. Das ist z.B. sinnvoll, wenn man andere Pfade nutzen will, als die Standard-Vorgaben.

Ein anderer Weg, Pfade korrekt einzustellen, ist die Übergabe von Optionen an die setup.rb. Mit ruby setup.rb --help kann man sich auflisten lassen, was denn da so alles geht.

Unter anderem finden wir hier die Option --site-ruby=path, mit der wir den Installationspfad für das Module verändern können. Es ist eine Option, die nur bei der Task "config" gültig ist. Setup kennt ja 3 Tasks, config, setup und install, wie der obige 3-Satz schon gezeigt hat. Wir könnten also schreiben:

 
# ruby setup.rb config --site-ruby=/mein/verzeichniss

Den Aufruf der Task setup können wir uns in diesem einfachen Beispiel eigentlich sparen, es gibt ja nichts, was dort getan werden könnte. Der setup-Task ist vor allem dazu da, Programme zu compilieren, Zieldateien aus Quelldateien zu erzeugen, plattformspezifische Sachen in den Code einzufügen usw.

Bevor wir jetzt den install-Task aufrufen und damit wirklich installieren, starten wir diesen mit der Option --no-harm. Damit wird nur so getan als ob, es wird nicht wirklich installiert. Praktisch, um zu beobachten, was installiert würde.

 
# ruby setup.rb install --no-harm
---> lib
mkdir -p /usr/local/lib/site_ruby/1.6/
---> lib/myClasses
mkdir -p /usr/local/lib/site_ruby/1.6/myClasses
install saphir.rb /usr/local/lib/site_ruby/1.6/myClasses
<--- lib/myClasses
<--- lib

Hier lässt sich also genau erkennen, dass Verzeichnisse angelegt würden und dann saphir.rb an entsprechende Stelle installiert würde.

Wenn wir damit zufrieden sind, dann können wir es nun ohne --no-harm wirklich installieren.

Man erkennt hier auch, dass das Unterverzeichnis ./lib in unserem Paket als Basis für die Installation nach site-ruby verwenden wird. Legt man dort Unterverzeichnisse an, werden diese später auch im Installationsziel angelegt.

Übrigens: Welche Dateien installiert wurden, findet man in der Datei InstalledFiles, die im Projekt-Hauptverzeichnis liegen sollte, wo sich auch die setup.rb befindet. Der Mechanismus hier ist intelligent, installiert wird nur, wenn noch keine identischen Dateien bereits vorhanden sind. Also nicht wundern, wenn man ein zweites mal installiert und nichts in InstalledFiles vorfindet.

Soweit... Mit diesem Wissen ausgestattet ist man in der Lage, seine entwickelten Ruby-Module sauber zu installieren. Das Paket braucht nur noch eine README, wird noch mit etwas Dokumentation gewürzt, dann mit tar zusammengepackt und einer Verbreitung als freie Software steht nichts mehr im Wege.

3. Eigene Programme installieren

Das setup.rb erkennt automatisch nicht nur das lib-Verzeichnis im Paket. Folgende Verzeichnisse werden beim Installationsprozess in der Art verteilt:

Verzeichniswird installiert nach...
./binbin-dir, z.B. /usr/bin
./datadata-dir, z.B. /usr/share
./libsite-ruby, z.B. /usr/local/lib/site_ruby/1.6
./extso-dir, z.B. /usr/local/lib/site_ruby/1.6/i386-linux/

Dateien, die an diese Orte installiert werden sollen, können in der gleichen Art wie Module einfach in diese Unterverzeichnisse abgelegt werden. Natürlich kann man z.B. in ./data auch weitere Untervzeichnisse anlegen, die dann bei der Installation auf dem Zielsystem erzeugt werden.

Jeden dieser Pfade kann man auch beim config-Task manuell setzen:

 
# ruby setup.rb config --bin-dir=/usr/local/bin

Manchmal reichen die vorgegebenen Pfade nicht aus oder man muss während der Installation weitere Aktionen durchführen. Hier kann setup.rb sehr komfortabel erweitert werden.

4. Metaconfig - neue Setupvariablen definieren

Oft braucht man weitere Konfigurations-Variablen, die sowohl mit einem Standardwert belegt werden, die man aber auch manuell verändern kann.

Für diesen Zweck muss im Paket-Root die Datei metaconfig angelegt werden. Hier legt man mittels add_path_config, add_bool_config oder add_config diese Variablen an:

 
# File metaconfig:
add_path_config( "sdata", "/usr/lib", "Application state data" )
add_bool_config( "zip-support", true, "With zip support?" )
add_config( "wikiname", "string", "mywiki", "Wikiname" )

Im Beispiel wird zuerst eine path-Variable mit dem Namen sdata angelegt, Defaultwert ist "/usr/lib" und die Beschreibung ist "Application state data". Wenn man sich mit ruby setup.rb --help die Hilfe ausgibt, sieht man hier auch schon die Auflistung dieser Variablen. Hier wird der Variablentyp, der Name, die Defaultbelegung und die Beschreibung ausgegeben. Für boolesche Variablen gibt es die Funktion add_bool_config. Eine allgemeingültigere Funktion ist add_config, mit der man beliebige Datentypen von Variablen festlegen kann. Der Variablentyp wird hier an zweiter Stelle übergeben, er wird jedoch nicht irgendwie von setup.rb ausgewertet. Er dient lediglich der Ausgabe unter --help, hat also beschreibenden Charakter.

Mit diesen Funktionen können wir also neue Variablen definieren, die nach dem config-Task in der config.save abgespeichert werden und die über Optionen beim Aufruf auch mit neuen Werten belegt werden können. Natürlich müssen wir diese Variablen auch irgendwie auswerten oder nutzen, sonst macht das ja wenig Sinn. Hierzu jedoch später.

Übrigens kann man Variablen auch in Wertzuweisungen anderer Variablen verwenden, wie das ja mit $prefix z.B. geschieht. Wir können also neue Variablen auch für solche Zwecke anlegen. Leider scheint das bisherige Skript nicht mehrere hintereinandergehängte Variablen aufzulösen, also z.B. bin-dir=$root$prefix/bin.

Eine weitere Funktion darf in der Datei metaconfig auftreten: set_config_default(confname, val). Hiermit kann man die Defaultbelegung von Variablen, wie sie durch setup.rb vorgegeben wird, verändern. Man kann damit z.B.das bin-Verzeichnis nach "/usr/local/bin" verlagern, wenn dies die neue Defaulteinstellung sein soll. Natürlich kann der Benutzer diesen Wert durch --bin-dir=path wieder überschreiben.

Eine letzte Funktion ist remove_config(confname), mit der man eine Variable komplett von der Konfiguriation entfernen kann.

5. Hook Skripts - eigenen Setup Code einbringen

Das setup.rb Skript nutzt sogenannte Hook-Skripts, um externen Code in die Ausführung mit einzuschleusen. So wird z.B. vor Start der config-Task die Datei pre-config.rb im Paket-Root gesucht. Ist sie vorhanden, wird sie zuerst ausgeführt, danach der setup-Code von setup.rb selbst und dann die Hook-Datei post-config.rb.

In jeder Task gibt es die Möglichkeit von Hook-Skripts, also pre-config.rb, post-config.rb, pre-setup.rb, post-setup.rb, pre-install.rb und post-install.rb. Damit ist schon eine Menge Eingriffsmöglichkeit für eigenen Code gegeben.

Diese Hook-Skripts werden auch im Kontext der Klasse Installer ausgeführt, womit man Zugriff auf einige API-Methoden hat. Diese Methoden stellen einem praktische Helfer zur Verfügung, die man bei Setup-Aktionen so braucht. Hier sind die wichtigsten:

MethodeBeschreibung
mkdir_p( dirname, prefix = nil )Verzeichnis erstellen, wie mkdir -p
rm_f( fname )Datei löschen, wie rm -f
rm_rf( dn )Verzeichnis mit Inhalt löschen, wie rm -rf
move_file( src, dest )Datei verschieben
install( from, dest, mode, prefix = nil )Datei installieren.
command( str )Shell Kommando ausführen
ruby( str )Ruby-Skript ausführen
make( task = '' )Make ausführen
all_files_in( dirname )Alle Dateien eines Verzeichnisses zurückgeben.
all_dirs_in( dirname )Alle Verzeichnisse in einem Verzeichnis zurückgeben.
get_config( key )Variablen-Inhalt der Variable key zurückgeben
config( key )Synonym zu get_config.
curr_objdirAktuelles Objekt-Dir.
srcfileAkutelles Sourcefile.
srcexist?( path )Source existiert?
srcdirectory?( path )Source-Dir existiert?
srcfile?( file )Source-File existiert?
srcentries( path )Source-Einträge zurückgeben
srcfiles( path)Source-Files
srcdirectories( path )Source-Dirs

Zum kopieren, löschen, erstellen, installieren sollte man diese Funktionen nutzen, auch wenn man es anders tun könnte. Denn diese Funktionen geben auch eine Meldung auf dem Bildschirm aus, was sie tun, insofern --verbose eingeschaltet ist. Das hilft dem Benutzer, genau nachvollziehen zu können, was bei der Installation passiert.

Ansonsten kann man in den Hook-Skripten beliebigen Ruby-Code unterbringen.

Es gibt auch die Möglichkeit, in den einzelnen Unterverzeichnissen (bin, ext, lib, data) Hook-Skripts unterzubringen. Wenn setup.rb ausgeführt wird, durchläuft es ja Verzeichnis für Verzeichnis, was es z.B. durch "--->bin" für den Eintritt und "<---bin" bei Austritt auf den Bildschirm ausgibt. Wenn man nun z.B. bestimmte Aktionen nur im bin-Verzeichnis machen möchte, kann man dort ein Hook-Skript unterbringen.

Eine weitere interessante Möglichkeit ist die Erweiterung der Verzeichnisse, die durchlaufen werden, default sind es ja bin, ext, lib, data. Oft braucht man z.B. ein Verzeichnis für Statusdaten eines Programms, die typisch unter /var/lib abgelegt werden. Man könnte nun ein Unterverzeichnis sdata im Paket anlegen und dies dann wie folgt in einer pre-install.rb einbinden:

 
FILETYPES << "sdata"

def install_dir_sdata(rel)
  install_files collect_filenames_auto(), config('sdata-dir') + '/' + rel, 0644
end

Zuerst erweitern wir FILETYPES durch sdata, damit auch das Unterverzeichnis sdata durchlaufen wird. FILETYPES ist eine Konstante in der Klasse Installer, die definiert, welche Verzeichnisse durchlaufen werden sollen.

Dann braucht es noch eine Funktion, deren Name mit install_dir_ beginnt und der dann der Name des Unterverzeichnisses angehängt ist. An diese Konvention muss man sich halten und dies macht auch deutlich, dass z.B. ein Unterverzeichnis kein Bindestrich enthalten darf. Einfach, weil man daraus keinen Funktionsnamen backen kann. Auch viele Sonderzeichen werden nicht funktionieren.

Die Funktion install_dir_sdata(rel) habe ich hier aus der setup.rb rüberkopiert, als Vorlage diente mir def install_dir_lib(rel).

Im setup.rb Skript findet man irgendwo die Zeile REJECT_DIRS = %w( CVS SCCS RCS CVS.adm ). Diese sorgt dafür, dass evtl. vorhandene CVS-Unterverzeichnisse (werden vom Code-Version-System zur Versionkontrolle automatisch angelegt) nicht mit installiert werden. Hierüber könnte man auch weitere Verzeichnisse generell von der Installation ausschließen.

Mit diesen wenigen Zeilen haben wir es geschafft, dass jetzt auch das Verzeichnis sdata durchlaufen wird und die Files nach sdata-dir installiert werden. Hierzu müssen wir natürlich sdata-dir, wie oben beschrieben, in die metaconfig mit aufnehmen.

6. Shebang

Ruby-Skripte enthalten in der ersten Zeile normal eine Angabe des Befehlsinterpreters (Shebang-Zeile). Diese muss für das aktuelle System korrekt gesetzt sein. Diese Zeile wird von setup.rb automatisch korrekt angepasst. Nicht angepasst wird sie, wenn "#!/usr/bin/env ruby" enthalten ist, weil das in diesem Fall nicht nötig ist. Generell wird nichts angepasst, wo ein anderes Programm als ruby angegeben ist.

7. Skripts während des Setups anpassen

Oft ist es nötig, dass Skripts an die Umgebung angepasst werden müssen, bevor sie installiert werden. Dies kann z.B. dann der Fall sein, wenn ein Skript auf eine Config-Datei zugreifen muss, deren Standort erst bei der Installation bekannt wird.

In diesem Fall sollte man die Skripte im Paket-Root oder einem Extra-Unterverzeichnis ablegen. Im setup-Task dann liest man über pre-setup.rb das gesamte Skript, macht die Änderungen und schreibt es nach ./bin. Von dort wird es dann ja automatisch durch die install-Task installiert.

Auch lassen sich über diesen Weg mehrere Skriptdateien zu einem Skript zusammenschrauben, was man dann auf dem System installiert. Das macht es mitunter übersichtlicher und einfacher wartbar. So kann man es sich ggf. sparen, eine Reihe Module zu installieren. Stattdessen fügt man einfach alles in einem Skript zusammen und installiert dies. Man könnte das mit statischem Linken bei C-Programmen vergleichen, anstatt auf Bibliotheken dynamisch zurückzugreifen.

Ein einfaches Beispiel, wie man sowas bewerkstelligt, ist das asm.rb Skript im setup-Paket selber. Denn setup.rb ist auch ein aus mehreren Einzel-Skripts zusammengesetztes Ganzes.

8. Freie Softwarepakete schnüren

Sobald man Software-Pakete der Welt verfügbar macht, ist es wichtig, sich einige weiterführende Gedanken zu machen. Soll sich ein Paket gut verbreiten, muss die Einstiegshürde gering sein. Keiner quält sich gerne stundenlang mit etwas herum, wo er noch nicht mal weiß, ob ein Paket überhaupt brauchbar für ihn ist.

Hier mal einige generelle Anregungen in diesem Zusammenhang:

  • In der freien Software Community haben sich bestimmte Formen entwickelt, wie man etwas tut. Manche davon sind in Standards festgeschrieben, manches sind Empfehlungen. Oft ist es aber so, dass Dinge einfach auf bestimmte Weise getan werden, ohne dass darüber bewusst reflektiert wurde und ohne dass darüber irgendwelche Unterlagen existieren. Man macht es einfach so, weil es praktisch ist. Man lernt es irgendwo kennen und ahmt es dann nach. Es ist von daher wichtig, sich andere Projekte anzuschauen und das zu übernehmen, was man dort für sinnvoll erachtet.
  • Wenn du ein Problem zu lösen versuchst, schaue immer erstmal, ob es nicht schon ähnliches gibt. Nutze lieber etwas, was schon da ist, vor allem dann, wenn viele mit deiner Problemlösung umgehen müssen. Denn keiner hat Lust die hundertste Problemlösung für etwas zu verstehen, wo es doch eine gute brauchbare Form schon gibt. Das betrifft z.B. das Format für Konfigurationsdateien. Nutze bekannte Formate, das erleichtert allen den Umgang, weil sie auf etwas zurückgreifen können, was sie schon kennen. Es ist wirklich intelligent, wenn man anderen Software präsentiert, die sie in vielen Elementen schon kennen. Der Einstieg fällt dann leichter. Viele Software hat sich deshalb so schnell verbreitet, weil sie sich an Strukturen gehalten hat, die geläufig waren.
  • Jeder muss blitzschnell verstehen können, was deine Software tut, wofür sie gut ist. Man muss sich manchmal durch Berge von Software wühlen, um was passendes zu finden. Hier ist es wichtig, schnell entscheiden zu können, ob diese Software dem entspricht, was man sucht.
  • Ich finde es hilfreich und wichtig, die Konzepte und das Design einer Software zu verstehen, denn nur so kann ich abschätzen, was sie leisten kann. Nur so bekomme ich ein Verständnis von der Funktionsweise. Eine gute Dokumentation enthält eine Designbeschreibung.
  • Menschen müssen eine erste Begeisterung für eine Software bekommen, damit der Wille wächst, sich damit auseinanderzusetzen. Nichts ist schlimmer, als Software, bei der man erst 3 Stunden rumfummeln muss, bis man ein minimales Ergebnis sieht. Gut ist dagegen Software, die man blitzschnell installieren und mit irgendeiner Beispielkonfiguration benutzen kann. Dann kann man sofort die Software erleben. Wenn ich hier feststelle, dass ich das brauche, dann bin ich auch bereit, mehr Zeit zu investieren. Gut sind auch Demonstrationen im Internet oder eine Präsentation als Teil der Dokumentation.

Und hier einige konkrete Hinweise für Ruby-Pakete:

  • Ins Paket-Root gehört eine README. Dort kommt in Kurzform rein, was das Paket tut, wie man es installiert, unter welchen Plattformen es läuft, welche Lizenz benutzt wird, wer der Autor ist (am besten mit Mailadresse), von welchen Komponenten die Software abhängt bzw. was sie für eine Umgebung benötigt. Auch eine kurze Info, in welchem Stadium sie ist, ist hilfreich (alpha, beta, stable...). Das setup-Paket enthält eine Datei namens Template.README, die man als Vorlage verwenden kann.
  • Zusätzlich kann man ins Paket-Root eine Datei namens LICENSE legen, in der die Lizenzbedingungen aufgeführt sind.
  • Die Dokumentation kann man z.B. in einem Verzeichnis doc ablegen. Textformat ist immer und überall lesbar, html-Format wäre auch eine Möglichkeit. Eine Kurzreferenz oder Manpage im Textformat hat den Vorteil, dass man sie auch problemlos auf einer Text-Konsole lesen kann. Am besten schreibt man Doku in einem Quellformat, woraus dann viele andere Formate generiert werden können. In Ruby gibt es ja auch den Weg über das eingebaute Dokumentations-Format, RD (rdoc). Viele schreiben so ihre Doku direkt in den Quellcode. Das ist praktisch, man sollte allerdings auch die Laufzeitkonsequenzen beachten. Skripte, die sehr oft neu geladen werden, müssen auch immer wieder diese Dokumentation mit einlesen und das kostet Laufzeit. Allerdings ist dieses Problem nur in Spezialfällen von Belang. Oft überwiegt die praktische Seite von Inline-Dokumentationen.
  • Pfade können auf dem Zielsystem völlig anders gewählt sein. Man sollte beim Design daran denken.
  • Derzeit gibt es 2 zentrale Adressen, wo man ruby-Skripte veröffentlichen kann: Das raa-Archiv auf http://www.ruby-lang.org und http://www.rubyforge.org. Am besten, man stellt sie auf beiden Systemen online oder verweist zumindest untereinander. Mir scheint es so, dass rubyforge die Plattform der Zukunft werden wird.
  • Mitunter kann es gut sein, ein paar Tests mit hineinzupacken, mit denen man die ordnungsgemäße Funktion auf der Zielplattform überprüfen kann. Auch ein paar Beispiele erleichtern den Einstieg.
  • Ein Test auf mehreren Plattformen ist viel wert, weil man so einige Plattformabhängigkeiten auflösen kann.

Das alles sind Ideen, die eine gute Richtung weisen sollen, sie sind keine Voraussetzungen, um Software zu veröffentlichen. Denn all das kostet auch Zeit und Arbeit, die man vielleicht nicht aufbringen will oder kann. Auch wenn wichtige Dinge fehlen, es finden sich immer Menschen, für die auch so ein "unfertiges Paket" eine unschätzbare Hilfe ist. Und als Entwickler bekommt man wertvolles Feedback. Es lohnt sich also, schon früh zu veröffentlichen. Besser werden kann man immer noch.

8. Referenzen

Die Dokumentation hier bezieht sich auf das Setup-Paket Version 3.2.2.

  • [1] englische Originaldoku im setup.rb Paket unter ./doc.en
  • [2] Paketierungshinweise im rubygarden Wiki
  • [3] Homepage setup.rb von Minero Aoki
  • [4] RubyGems Bibliotheken Installationssystem
    Dieses System erfährt gerade (2004/2005) einen unglaublichen Hype. Es ist ein Paket-Installationssystem, ähnlich apt-get bei Debian. Man kann hierüber Ruby *.gem Pakete komfortabel installieren, lokal und übers Netzwerk. In vielen Bereichen wird es das Setup Paket, was hier beschrieben wurde, ablösen. Viele Module-Entwickler bieten ihre Bibliotheken bereits als gem-Paket an.

9. Fehler, Ergänzungen?

Habe ich etwas vergessen? Kann etwas verbessert werden? Haben Sie eine Idee? Ich freue mich über Feedback zu diesem Text.

10. Changelog

  • 02.03.2005 Hinweis auf RubyGems
  • 13.11.2004 Rev 0.11: Umformatierung fürs Wiki
  • 28.02.2004 Rev 0.1: Erste Veröffentlichung.

11. Nachträge

12. Copyright und Hinweise

Copyright (c) 2003 Winfried Mueller, www.reintechnisch.de

Es wird die Erlaubnis gegeben dieses Dokument zu kopieren, zu verteilen und/oder zu verändern unter den Bedingungen der GNU Free Documentation License, Version 1.1 oder einer späteren, von der Free Software Foundation veröffentlichten Version; mit keinen unveränderlichen Abschnitten, mit keinen Vorderseitentexten, und keinen Rückseitentexten.

Eine Kopie dieser Lizenz finden Sie unter GNU Free Documentation License.

Eine inoffizielle Übersetzung finden Sie unter GNU Free Documention License, deutsch.

In diesem Artikel werden evtl. eingetragene Warenzeichen, Handelsnamen und Gebrauchsnamen verwendet. Auch wenn diese nicht als solche gekennzeichnet sind, gelten die entsprechenden Schutzbestimmungen.

Alle Informationen in diesem Artikel wurden mit Sorgfalt erarbeitet. Trotzdem können Inhalte fehlerhaft oder unvollständig sein. Ich übernehme keinerlei Haftung für eventuelle Schäden oder sonstige Nachteile, die sich durch die Nutzung der hier dargebotenen Informationen ergeben.

Sollten Teile dieser Hinweise der geltenden Rechtslage nicht entsprechen, bleiben die übrigen Teile davon unberührt.