Revision 4fd8bdbf
Von Moritz Bunkus vor etwa 18 Jahren hinzugefügt
SL/DBUpgrade2.pm | ||
---|---|---|
package SL::DBUpgrade2;
|
||
|
||
require Exporter;
|
||
@ISA = qw(Exporter);
|
||
|
||
@EXPORT = qw(parse_dbupdate_controls sort_dbupdate_controls);
|
||
|
||
sub parse_dbupdate_controls {
|
||
$main::lxdebug->enter_sub();
|
||
|
||
my ($form, $dbdriver) = @_;
|
||
|
||
my $locale = $main::locale;
|
||
|
||
local *IN;
|
||
my %all_controls;
|
||
|
||
my $path = "sql/${dbdriver}-upgrade2";
|
||
|
||
foreach my $file_name (<$path/*.sql>, <$path/*.pl>) {
|
||
next unless (open(IN, $file_name));
|
||
|
||
my $file = $file_name;
|
||
$file =~ s|.*/||;
|
||
|
||
my $control = {
|
||
"priority" => 1000,
|
||
"depends" => [],
|
||
};
|
||
|
||
while (<IN>) {
|
||
chomp();
|
||
next unless (/^(--|\#)\s*\@/);
|
||
s/^(--|\#)\s*\@//;
|
||
s/\s*$//;
|
||
next if ($_ eq "");
|
||
|
||
my @fields = split(/\s*:\s*/, $_, 2);
|
||
next unless (scalar(@fields) == 2);
|
||
|
||
if ($fields[0] eq "depends") {
|
||
push(@{$control->{"depends"}}, split(/\s+/, $fields[1]));
|
||
} else {
|
||
$control->{$fields[0]} = $fields[1];
|
||
}
|
||
}
|
||
|
||
_control_error($form, $file_name,
|
||
$locale->text("Missing 'tag' field."))
|
||
unless ($control->{"tag"});
|
||
|
||
_control_error($form, $file_name,
|
||
$locale->text("The 'tag' field must only consist of " .
|
||
"alphanumeric characters or the carachters " .
|
||
"- _ ( )"))
|
||
if ($control->{"tag"} =~ /[^a-zA-Z0-9_\(\)\-]/);
|
||
|
||
_control_error($form, $file_name,
|
||
sprintf($locale->text("More than one control file " .
|
||
"with the tag '%s' exist."),
|
||
$control->{"tag"}))
|
||
if (defined($all_controls{$control->{"tag"}}));
|
||
|
||
_control_error($form, $file_name,
|
||
sprintf($locale->text("Missing 'description' field.")))
|
||
unless ($control->{"description"});
|
||
|
||
$control->{"priority"} *= 1;
|
||
$control->{"priority"} = 1000 unless ($control->{"priority"});
|
||
|
||
$control->{"file"} = $file;
|
||
|
||
map({ delete($control->{$_}); } qw(depth applied));
|
||
|
||
$all_controls{$control->{"tag"}} = $control;
|
||
|
||
close(IN);
|
||
}
|
||
|
||
foreach my $control (values(%all_controls)) {
|
||
foreach my $dependency (@{$control->{"depends"}}) {
|
||
_control_error($form, $control->{"file"},
|
||
sprintf($locale->text("Unknown dependency '%s'."),
|
||
$dependency))
|
||
if (!defined($all_controls{$dependency}));
|
||
}
|
||
|
||
map({ $_->{"loop"} = 0; } values(%all_controls));
|
||
_check_for_loops($form, $control->{"file"}, \%all_controls,
|
||
$control->{"tag"});
|
||
}
|
||
|
||
map({ _dbupdate2_calculate_depth(\%all_controls, $_->{"tag"}) }
|
||
values(%all_controls));
|
||
|
||
$main::lxdebug->leave_sub();
|
||
|
||
return \%all_controls;
|
||
}
|
||
|
||
sub _check_for_loops {
|
||
my ($form, $file_name, $controls, $tag, @path) = @_;
|
||
|
||
push(@path, $tag);
|
||
|
||
_control_error($form, $file_name,
|
||
$main::locale->text("Dependency loop detected:") .
|
||
" " . join(" -> ", @path))
|
||
if ($controls->{$tag}->{"loop"});
|
||
|
||
$controls->{$tag}->{"loop"} = 1;
|
||
map({ _check_for_loops($form, $file_name, $controls, $_, @path); }
|
||
@{$controls->{$tag}->{"depends"}});
|
||
}
|
||
|
||
sub _control_error {
|
||
my ($form, $file_name, $message) = @_;
|
||
|
||
my $form = $main::form;
|
||
my $locale = $main::locale;
|
||
|
||
$form->error(sprintf($locale->text("Error in database control file '%s': %s"),
|
||
$file_name, $message));
|
||
}
|
||
|
||
sub _dbupdate2_calculate_depth {
|
||
$main::lxdebug->enter_sub();
|
||
|
||
my ($tree, $tag) = @_;
|
||
|
||
my $node = $tree->{$tag};
|
||
|
||
return $main::lxdebug->leave_sub() if (defined($node->{"depth"}));
|
||
|
||
my $max_depth = 0;
|
||
|
||
foreach $tag (@{$node->{"depends"}}) {
|
||
_dbupdate2_calculate_depth($tree, $tag);
|
||
my $value = $tree->{$tag}->{"depth"};
|
||
$max_depth = $value if ($value > $max_depth);
|
||
}
|
||
|
||
$node->{"depth"} = $max_depth + 1;
|
||
|
||
$main::lxdebug->leave_sub();
|
||
}
|
||
|
||
sub sort_dbupdate_controls {
|
||
return
|
||
sort({ $a->{"depth"} != $b->{"depth"} ? $a->{"depth"} <=> $b->{"depth"} :
|
||
$a->{"priority"} != $b->{"priority"} ?
|
||
$a->{"priority"} <=> $b->{"priority"} :
|
||
$a->{"tag"} cmp $b->{"tag"} } values(%{$_[0]}));
|
||
}
|
||
|
||
|
||
1;
|
SL/User.pm | ||
---|---|---|
|
||
package User;
|
||
|
||
use SL::DBUpgrade2;
|
||
|
||
sub new {
|
||
$main::lxdebug->enter_sub();
|
||
|
||
... | ... | |
'$myconfig{tel}', 'user')|;
|
||
$dbh->do($query);
|
||
}
|
||
|
||
$self->create_schema_info_table($form, $dbh);
|
||
|
||
$dbh->disconnect;
|
||
|
||
$rc = 0;
|
||
|
||
if (&update_available($myconfig{"dbdriver"}, $dbversion)) {
|
||
my $controls =
|
||
parse_dbupdate_controls($form, $myconfig{"dbdriver"});
|
||
|
||
map { $form->{$_} = $myconfig{$_} }
|
||
qw(dbname dbhost dbport dbdriver dbuser dbpasswd dbconnect);
|
||
map({ $form->{$_} = $myconfig{$_} }
|
||
qw(dbname dbhost dbport dbdriver dbuser dbpasswd dbconnect));
|
||
|
||
if (update_available($myconfig{"dbdriver"}, $dbversion) ||
|
||
update2_available($form, $controls)) {
|
||
|
||
$form->{"stylesheet"} = "lx-office-erp.css";
|
||
$form->{"title"} = $main::locale->text("Dataset upgrade");
|
||
... | ... | |
}
|
||
|
||
# update the tables
|
||
open FH, ">$userspath/nologin" or die "
|
||
$!";
|
||
open(FH, ">$userspath/nologin") or die("$!");
|
||
|
||
# required for Oracle
|
||
$form->{dbdefault} = $sid;
|
||
... | ... | |
$SIG{QUIT} = 'IGNORE';
|
||
|
||
$self->dbupdate($form);
|
||
$self->dbupdate2($form, $controls);
|
||
|
||
# remove lock file
|
||
unlink "$userspath/nologin";
|
||
unlink("$userspath/nologin");
|
||
|
||
print($form->parse_html_template("dbupgrade/footer"));
|
||
|
||
... | ... | |
sub process_query {
|
||
$main::lxdebug->enter_sub();
|
||
|
||
my ($self, $form, $dbh, $filename, $version) = @_;
|
||
my ($self, $form, $dbh, $filename, $version_or_control) = @_;
|
||
|
||
# return unless (-f $filename);
|
||
|
||
... | ... | |
}
|
||
}
|
||
|
||
if ($version) {
|
||
if (ref($version_or_control) eq "HASH") {
|
||
$dbh->do("INSERT INTO schema_info (tag, login) VALUES (" .
|
||
$dbh->quote($version_or_control->{"tag"}) . ", " .
|
||
$dbh->quote($form->{"login"}) . ")");
|
||
} elsif ($version_or_control) {
|
||
$dbh->do("UPDATE defaults SET version = " . $dbh->quote($version));
|
||
}
|
||
$dbh->commit();
|
||
... | ... | |
return ($#upgradescripts > -1);
|
||
}
|
||
|
||
sub create_schema_info_table {
|
||
$main::lxdebug->enter_sub();
|
||
|
||
my ($self, $form, $dbh) = @_;
|
||
|
||
my $query = "SELECT tag FROM schema_info LIMIT 1";
|
||
if (!$dbh->do($query)) {
|
||
$query =
|
||
"CREATE TABLE schema_info (" .
|
||
" tag text, " .
|
||
" login text, " .
|
||
" itime timestamp DEFAULT now(), " .
|
||
" PRIMARY KEY (tag))";
|
||
$dbh->do($query) || $form->dberror($query);
|
||
}
|
||
|
||
$main::lxdebug->leave_sub();
|
||
}
|
||
|
||
sub dbupdate {
|
||
$main::lxdebug->enter_sub();
|
||
|
||
... | ... | |
last if ($version < $mindb);
|
||
|
||
# apply upgrade
|
||
$main::lxdebug->message(DEBUG2, "Appliying Update $upgradescript");
|
||
$main::lxdebug->message(DEBUG2, "Applying Update $upgradescript");
|
||
if ($file_type eq "sql") {
|
||
$self->process_query($form, $dbh, "sql/" . $form->{"dbdriver"} . "-upgrade/$upgradescript", $str_maxdb);
|
||
} else {
|
||
... | ... | |
return $rc;
|
||
}
|
||
|
||
sub dbupdate2 {
|
||
$main::lxdebug->enter_sub();
|
||
|
||
my ($self, $form, $controls) = @_;
|
||
|
||
$form->{sid} = $form->{dbdefault};
|
||
|
||
my @upgradescripts = ();
|
||
my ($query, $sth, $tag);
|
||
my $rc = -2;
|
||
|
||
@upgradescripts = sort_dbupdate_controls($controls);
|
||
|
||
foreach my $db (split / /, $form->{dbupdate}) {
|
||
|
||
next unless $form->{$db};
|
||
|
||
# strip db from dataset
|
||
$db =~ s/^db//;
|
||
&dbconnect_vars($form, $db);
|
||
|
||
my $dbh =
|
||
DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
|
||
or $form->dberror;
|
||
|
||
map({ $_->{"applied"} = 0; } @upgradescripts);
|
||
|
||
$query = "SELECT tag FROM schema_info";
|
||
$sth = $dbh->prepare($query);
|
||
$sth->execute() || $form->dberror($query);
|
||
while (($tag) = $sth->fetchrow_array()) {
|
||
$controls->{$tag}->{"applied"} = 1 if (defined($controls->{$tag}));
|
||
}
|
||
$sth->finish();
|
||
|
||
my $all_applied = 1;
|
||
foreach (@upgradescripts) {
|
||
if (!$_->{"applied"}) {
|
||
$all_applied = 0;
|
||
last;
|
||
}
|
||
}
|
||
|
||
next if ($all_applied);
|
||
|
||
foreach my $control (@upgradescripts) {
|
||
next if ($control->{"applied"});
|
||
|
||
$control->{"file"} =~ /\.(sql|pl)$/;
|
||
my $file_type = $1;
|
||
|
||
# apply upgrade
|
||
$main::lxdebug->message(DEBUG2, "Applying Update $control->{file}");
|
||
print($form->parse_html_template("dbupgrade/upgrade_message2",
|
||
$control));
|
||
|
||
if ($file_type eq "sql") {
|
||
$self->process_query($form, $dbh, "sql/" . $form->{"dbdriver"} .
|
||
"-upgrade2/$control->{file}", $control);
|
||
} else {
|
||
$self->process_perl_script($form, $dbh, "sql/" . $form->{"dbdriver"} .
|
||
"-upgrade2/$control->{file}", $control);
|
||
}
|
||
}
|
||
|
||
$rc = 0;
|
||
$dbh->disconnect;
|
||
|
||
}
|
||
|
||
$main::lxdebug->leave_sub();
|
||
|
||
return $rc;
|
||
}
|
||
|
||
sub update2_available {
|
||
$main::lxdebug->enter_sub();
|
||
|
||
my ($form, $controls) = @_;
|
||
|
||
map({ $_->{"applied"} = 0; } values(%{$controls}));
|
||
|
||
dbconnect_vars($form, $form->{"dbname"});
|
||
|
||
my $dbh =
|
||
DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) ||
|
||
$form->dberror;
|
||
|
||
my ($query, $tag, $sth);
|
||
|
||
$query = "SELECT tag FROM schema_info";
|
||
$sth = $dbh->prepare($query);
|
||
$sth->execute() || $form->dberror($query);
|
||
while (($tag) = $sth->fetchrow_array()) {
|
||
$controls->{$tag}->{"applied"} = 1 if (defined($controls->{$tag}));
|
||
}
|
||
$sth->finish();
|
||
$dbh->disconnect();
|
||
|
||
map({ $main::lxdebug->leave_sub() and return 1 if (!$_->{"applied"}) }
|
||
values(%{$controls}));
|
||
|
||
$main::lxdebug->leave_sub();
|
||
return 0;
|
||
}
|
||
|
||
sub create_config {
|
||
$main::lxdebug->enter_sub();
|
||
|
doc/sql-upgrade-dateien.txt | ||
---|---|---|
Neuer Mechanismus f?r SQL-Upgradedateien
|
||
----------------------------------------
|
||
|
||
Der alte Mechanismus f?r SQL-Upgradescripte, der auf einer
|
||
Versionsnummer beruht und dann in sql/Pg-upgrade nach einem Script f?r
|
||
diese Versionsnummer sucht, schr?nkt sehr ein, z.B. was die parallele
|
||
Entwicklung im stable- und unstable-Baum betrifft.
|
||
|
||
Dieser Mechanismus wurde f?r Lx-Office 2.4.1 deutlich erweitert. Es
|
||
werden weiterhin alle Scripte aus sql/Pg-upgrade
|
||
ausgef?hrt. Zus?tzlich gibt es aber ein zweites Verzeichnis,
|
||
sql/Pg-upgrade2. In diesem Verzeichnis muss pro Datenbankupgrade eine
|
||
Datei existieren, die neben den eigentlich auszuf?hrenden SQL- oder
|
||
Perl-Befehlen einige Kontrollinformationen enth?lt.
|
||
|
||
Neu sind die Kontrollinformationen, die Abh?ngigkeiten und Priorit?ten
|
||
definieren k?nnen werden, sodass Datenbankscripte zwar in einer
|
||
sicheren Reihenfolge ausgef?hrt werden (z.B. darf ein "ALTER TABLE"
|
||
erst ausgef?hrt werden, wenn die Tabelle mit "CREATE TABLE" angelegt
|
||
wurde), diese Reihenfolge aber so flexibel ist, dass man keine
|
||
Versionsnummern mehr braucht.
|
||
|
||
Lx-Office merkt sich dabei, welches der Upgradescripte in
|
||
sql/Pg-upgrade2 bereits durchgef?hrt wurde und f?hrt diese nicht
|
||
erneut aus. Dazu dient die Tabelle "schema_info", die bei der
|
||
Anmeldung automatisch angelegt wird.
|
||
|
||
Format der Kontrollinformationen
|
||
--------------------------------
|
||
|
||
Die Kontrollinformationen sollten sich am Anfang der jeweiligen
|
||
Upgradedatei befinden. Jede Zeile, die Kontrollinformationen enth?lt,
|
||
hat dabei das folgende Format:
|
||
|
||
F?r SQL-Upgradedateien:
|
||
|
||
-- @key: value
|
||
|
||
|
||
F?r Perl-Upgradedateien:
|
||
|
||
# @key: value
|
||
|
||
|
||
Leerzeichen vor "value" werden entfern.
|
||
|
||
Die folgenden Schl?sselworte werden verarbeitet:
|
||
|
||
* tag: Wird zwingend ben?tigt. Dies ist der "Name" des
|
||
Upgrades. Dieser "tag" kann von anderen Kontrolldateien in ihren
|
||
Abh?ngigkeiten verwendet werden (Schl?sselwort "depends"). Der "tag"
|
||
ist auch der Name, der in der Datenbank eingetragen wird.
|
||
|
||
Normalerweise sollte die Kontrolldatei genau so hei?en wie der
|
||
"tag", nur mit der Endung ".sql" bzw. "pl".
|
||
|
||
Ein Tag darf nur aus alphanumerischen Zeichen sowie den Zeichen _ -
|
||
( ) bestehen. Insbesondere sind Leerzeichen nicht erlaubt und
|
||
sollten stattdessen mit Unterstrichen ersetzt werden.
|
||
|
||
* description: Ben?tigt. Eine Beschreibung, was in diesem Update
|
||
passiert. Diese wird dem Benutzer beim eigentlichen Datenbankupdate
|
||
angezeigt. W?hrend der Tag in englisch gehalten sein sollte, sollte
|
||
die Beschreibung auf Deutsch erfolgen.
|
||
|
||
* depends: Optional. Eine mit Leerzeichen getrennte Liste von "tags",
|
||
von denen dieses Upgradescript abh?ngt. Lx-Office stellt sicher,
|
||
dass die in dieser Liste aufgef?hrten Scripte bereits durchgef?hrt
|
||
wurden, bevor dieses Script ausgef?hrt wird.
|
||
|
||
Abh?ngigkeiten werden rekursiv betrachtet. Wenn also ein Script "b"
|
||
existiert, das von ?nderungen in "a" abh?ngt, und eine neue
|
||
Kontrolldatei f?r "c" erstellt wird, die von ?nderungen in "a" und
|
||
"b" abh?ngt, so gen?gt es, in "c" nur den Tag "b" als Abh?ngigkeit
|
||
zu definieren.
|
||
|
||
Es ist nicht erlaubt, sich selbst referenzierende Abh?ngigkeiten zu
|
||
definieren (z.B. "a" -> "b", "b" -> "c" und "c" -> "a").
|
||
|
||
* priority: Optional. Ein Zahlenwert, der die Reihenfolge bestimmt, in
|
||
der Scripte ausgef?hrt werden, die die gleichen Abh?ngigkeitstiefen
|
||
besitzen. Fehlt dieser Parameter, so wird der Wert 1000 benutzt.
|
||
|
||
Dies ist reine Kosmetik. F?r echte Reihenfolgen muss "depends"
|
||
benutzt werden. Lx-Office sortiert die auszuf?hrenden Scripte zuerst
|
||
nach der Abh?ngigkeitstiefe (wenn "z" von "y" abh?ngt und "y" von
|
||
"x", so hat "z" eine Abh?ngigkeitstiefe von 2, "y" von 1 und "x" von
|
||
0. "x" w?rde hier zuerst ausgef?hrt, dann "y", dann "z"), dann nach
|
||
der Priorit?t und bei gleicher Priorit?t alphabetisch nach dem
|
||
"tag".
|
||
|
||
Hilfsscript dbupgrade2_tool.pl
|
||
------------------------------
|
||
|
||
Um die Arbeit mit den Abh?ngigkeiten etwas zu erleichtern, existiert
|
||
ein Hilfsscript namens "scripts/dbupgrade2_tool.pl". Es muss aus dem
|
||
Lx-Office-ERP-Basisverzeichnis heraus aufgerufen werden. Dieses Tool
|
||
liest alle Datenbankupgradescripte aus dem Verzeichnis sql/Pg-upgrade2
|
||
aus. Es benutzt daf?r die gleichen Methoden wie Lx-Office selber,
|
||
sodass alle Fehlersituationen von der Kommandozeile ?berpr?ft werden
|
||
k?nnen.
|
||
|
||
Wird dem Script kein weiterer Parameter ?bergeben, so wird nur eine
|
||
?berpr?fung der Felder und Abh?ngigkeiten vorgenommen. Man kann sich
|
||
aber auch Informationen auf verschiedene Art ausgeben lassen:
|
||
|
||
1. Listenform: "./scripts/dbupgrade2_tool.pl --list"
|
||
|
||
Gibt eine Liste aller Scripte aus. Die Liste ist in der Reihenfolge
|
||
sortiert, in der Lx-Office die Scripte ausf?hren w?rde. Es werden
|
||
neben der Listenposition der Tag, die Abh?ngigkeitstiefe und die
|
||
Priorit?t ausgegeben.
|
||
|
||
2. Baumform: "./scripts/dbupgrade2_tool.pl --tree"
|
||
|
||
Listet alle Tags in Baumform basierend auf den Abh?ngigkeiten
|
||
auf. Die "Wurzelknoten" sind dabei die Scripte, von denen keine
|
||
anderen abh?ngen. Die Unterknoten sind Scripte, die beim
|
||
?bergeordneten Script als Abh?ngigkeit eingetragen sind.
|
||
|
||
3. Umgekehrte Baumform: "./scripts/dbupgrade2_tool.pl --rtree"
|
||
|
||
Listet alle Tags in Baumform basierend auf den Abh?ngigkeiten auf.
|
||
Die "Wurzelknoten" sind dabei die Scripte mit der geringsten
|
||
Abh?ngigkeitstiefe. Die Unterknoten sind Scripte, die das
|
||
?bergeordnete Script als Abh?ngigkeit eingetragen haben.
|
||
|
||
4. Baumform mit Postscriptausgabe: "./scripts/dbupgrade2_tool.pl --graphviz"
|
||
|
||
Ben?tigt das Tool "graphviz", um mit seiner Hilfe die Baumform aus
|
||
3. in eine Postscriptdatei namens "db_dependencies.ps"
|
||
auszugeben. Dies ist vermutlich die ?bersichtlichste Form, weil
|
||
hierbei jeder Knoten nur einmal ausgegeben wird. Bei den
|
||
Textmodusbaumformen hingegen k?nnen Knoten und all ihre
|
||
Abh?ngigkeiten mehrfach ausgegeben werden.
|
||
|
||
5. Scripte, von denen kein anderes Script abh?ngt:
|
||
"./scripts/dbupgrade2_tool.pl --nodeps"
|
||
|
||
Listet die Tags aller Scripte auf, von denen keine anderen Scripte
|
||
abh?ngen.
|
||
|
locale/de/admin | ||
---|---|---|
'Date Format' => 'Datumsformat',
|
||
'Delete' => 'L?schen',
|
||
'Delete Dataset' => 'Datenbank l?schen',
|
||
'Dependency loop detected:' => 'Schleife in den Abhängigkeiten entdeckt:',
|
||
'Directory' => 'Verzeichnis',
|
||
'Driver' => 'Treiber',
|
||
'Dropdown Limit' => 'Auswahllistenbegrenzung',
|
||
'E-mail' => 'eMail',
|
||
'Edit User' => 'Benutzerdaten bearbeiten',
|
||
'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
|
||
'Existing Datasets' => 'existierende Datenbanken',
|
||
'Fax' => 'Fax',
|
||
'File locked!' => 'Datei gesperrt!',
|
||
... | ... | |
'Login' => 'Anmeldung',
|
||
'Login name missing!' => 'Loginname fehlt.',
|
||
'Manager' => 'Manager',
|
||
'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
|
||
'Missing \'tag\' field.' => 'Fehlendes Feld \'tag\'.',
|
||
'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
|
||
'Multibyte Encoding' => 'Schriftsatz',
|
||
'Name' => 'Name',
|
||
'New Templates' => 'neue Vorlagen',
|
||
... | ... | |
'Stylesheet' => 'Stilvorlage',
|
||
'Supervisor' => 'Supervisor',
|
||
'Templates' => 'Vorlagen',
|
||
'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
|
||
'The following Datasets are not in use and can be deleted' => 'Die folgenden Datenbanken sind nicht in Verwendung und k?nnen gel?scht werden',
|
||
'The following Datasets need to be updated' => 'Folgende Datenbanken m?ssen aktualisiert werden',
|
||
'The passwords do not match.' => 'Die Passwörter stimmen nicht überein.',
|
||
'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'In diesem Schritt werden bestehende Datenbanken gesucht. Es werden noch keine ?nderungen vorgenommen!',
|
||
'To add a user to a group edit a name, change the login name and save. A new user with the same variables will then be saved under the new login name.' => 'Um einer Gruppe einen neuen Benutzer hinzuzuf?gen, ?ndern und speichern Sie am einfachsten einen bestehen den Zugriffsnamen. Unter dem neuen Namen wird dann ein Benutzer mit denselben Einstellungen angelegt.',
|
||
'Unknown dependency \'%s\'.' => 'Unbekannte Abhängigkeit \'%s\'.',
|
||
'Unlock System' => 'System entsperren',
|
||
'Update Dataset' => 'Datenbank aktualisieren',
|
||
'Use Templates' => 'benutze Vorlagen',
|
locale/de/all | ||
---|---|---|
'Ansprechpartner' => '',
|
||
'Application Error. No Format given!' => 'Fehler in der Anwendung. Das Format fehlt.',
|
||
'Application Error. Wrong Format: ' => 'Fehler in der Anwendung. Falsches Format: ',
|
||
'Applying <TMPL_VAR file ESCAPE=HTML>:' => 'Führe <TMPL_VAR file ESCAPE=HTML> aus:',
|
||
'Apr' => 'Apr',
|
||
'April' => 'April',
|
||
'Are you sure you want to delete Invoice Number' => 'Soll die Rechnung mit folgender Nummer wirklich gel?scht werden:',
|
||
... | ... | |
'Department deleted!' => 'Abteilung gel?scht.',
|
||
'Department saved!' => 'Abteilung gespeichert.',
|
||
'Departments' => 'Abteilungen',
|
||
'Dependency loop detected:' => 'Schleife in den Abhängigkeiten entdeckt:',
|
||
'Deposit' => 'Gutschrift',
|
||
'Description' => 'Beschreibung',
|
||
'Description missing!' => 'Beschreibung fehlt.',
|
||
... | ... | |
'Erl?se EU o. UStId' => 'Erlöse EU o. UStId',
|
||
'Erl?se Inland' => 'Erlöse Inland',
|
||
'Error' => 'Fehler',
|
||
'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
|
||
'Error!' => 'Fehler!',
|
||
'Exch' => 'Wechselkurs.',
|
||
'Exchangerate' => 'Wechselkurs',
|
||
... | ... | |
'Method' => 'Verfahren',
|
||
'Microfiche' => 'Mikrofilm',
|
||
'Minimum Amount' => 'Mindestbetrag',
|
||
'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
|
||
'Missing \'tag\' field.' => 'Fehlendes Feld \'tag\'.',
|
||
'Missing Method!' => 'Fehlender Voranmeldungszeitraum',
|
||
'Missing Preferences: Outputroutine disabled' => 'Die Ausgabefunktionen sind wegen unzureichender Voreinstellungen deaktiviert!',
|
||
'Missing Tax Authoritys Preferences' => 'Fehlende Angaben zum Finanzamt!',
|
||
... | ... | |
'Model' => 'Modell',
|
||
'Monat' => 'Monat',
|
||
'Monthly' => 'monatlich',
|
||
'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
|
||
'Multibyte Encoding' => 'Schriftsatz',
|
||
'MwSt. inkl.' => 'MwSt. inkl.',
|
||
'N/A' => 'N.Z.',
|
||
... | ... | |
'Templates' => 'Vorlagen',
|
||
'Terms missing in row ' => '+Tage fehlen in Zeile ',
|
||
'Terms: Net' => 'Zahlungsziel',
|
||
'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
|
||
'The base unit does not exist or it is about to be deleted in row %d.' => 'Die Basiseinheit in Zeile %d existiert nicht oder soll gelöscht werden.',
|
||
'The base unit does not exist.' => 'Die Basiseinheit existiert nicht.',
|
||
'The base unit relations must not contain loops (e.g. by saying that unit A\'s base unit is B, B\'s base unit is C and C\'s base unit is A) in row %d.' => 'Die Beziehungen der Einheiten dürfen keine Schleifen beinhalten (z.B. wenn gesagt wird, dass Einheit As Basiseinheit B, Bs Basiseinheit C und Cs Basiseinheit A ist) in Zeile %d.',
|
||
... | ... | |
'Unit' => 'Einheit',
|
||
'Unit of measure' => 'Ma?einheit',
|
||
'Units' => 'Einheiten',
|
||
'Unknown dependency \'%s\'.' => 'Unbekannte Abhängigkeit \'%s\'.',
|
||
'Unlock System' => 'System entsperren',
|
||
'Until' => 'Bis',
|
||
'Update' => 'Erneuern',
|
locale/de/am | ||
---|---|---|
'Department deleted!' => 'Abteilung gel?scht.',
|
||
'Department saved!' => 'Abteilung gespeichert.',
|
||
'Departments' => 'Abteilungen',
|
||
'Dependency loop detected:' => 'Schleife in den Abhängigkeiten entdeckt:',
|
||
'Description' => 'Beschreibung',
|
||
'Description missing!' => 'Beschreibung fehlt.',
|
||
'Discount' => 'Rabatt',
|
||
... | ... | |
'Erl?se EU m. UStId' => 'Erlöse EU m. UStId',
|
||
'Erl?se EU o. UStId' => 'Erlöse EU o. UStId',
|
||
'Erl?se Inland' => 'Erlöse Inland',
|
||
'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
|
||
'Expense' => 'Aufwandskonto',
|
||
'Expense Account' => 'Aufwandskonto',
|
||
'Expense/Asset' => 'Aufwand/Anlagen',
|
||
... | ... | |
'Link' => 'Verkn?pfungen',
|
||
'Long Dates' => 'Lange Monatsnamen',
|
||
'Long Description' => 'Langtext',
|
||
'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
|
||
'Missing \'tag\' field.' => 'Fehlendes Feld \'tag\'.',
|
||
'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
|
||
'Name' => 'Name',
|
||
'Netto Terms' => 'Zahlungsziel netto',
|
||
'No' => 'Nein',
|
||
... | ... | |
'Template Code' => 'Vorlagenk?rzel',
|
||
'Template Code missing!' => 'Vorlagenk?rzel fehlt!',
|
||
'Template saved!' => 'Schablone gespeichert!',
|
||
'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
|
||
'The base unit does not exist or it is about to be deleted in row %d.' => 'Die Basiseinheit in Zeile %d existiert nicht oder soll gelöscht werden.',
|
||
'The base unit does not exist.' => 'Die Basiseinheit existiert nicht.',
|
||
'The base unit relations must not contain loops (e.g. by saying that unit A\'s base unit is B, B\'s base unit is C and C\'s base unit is A) in row %d.' => 'Die Beziehungen der Einheiten dürfen keine Schleifen beinhalten (z.B. wenn gesagt wird, dass Einheit As Basiseinheit B, Bs Basiseinheit C und Cs Basiseinheit A ist) in Zeile %d.',
|
||
... | ... | |
'UStVA-Nr. 98' => 'Kz. 98',
|
||
'Umsatzsteuervoranmeldung' => 'Umsatzsteuervoranmeldung',
|
||
'Unit' => 'Einheit',
|
||
'Unknown dependency \'%s\'.' => 'Unbekannte Abhängigkeit \'%s\'.',
|
||
'Value' => 'Wert',
|
||
'Variable' => 'Variable',
|
||
'Warehouse deleted!' => 'Das Lager wurde gel?scht.',
|
locale/de/locales.pl | ||
---|---|---|
$basedir = "../..";
|
||
$bindir = "$basedir/bin/mozilla";
|
||
$dbupdir = "$basedir/sql/Pg-upgrade";
|
||
$dbupdir2 = "$basedir/sql/Pg-upgrade2";
|
||
$menufile = "menu.ini";
|
||
$submitsearch = qr/type\s*=\s*[\"\']?submit/i;
|
||
|
||
... | ... | |
@dbplfiles = grep { /\.pl$/ } readdir DIR;
|
||
closedir DIR;
|
||
|
||
opendir DIR, $dbupdir2 or die "$!";
|
||
@dbplfiles2 = grep { /\.pl$/ } readdir DIR;
|
||
closedir DIR;
|
||
|
||
# slurp the translations in
|
||
if (-f 'all') {
|
||
require "all";
|
||
... | ... | |
|
||
map({ handle_file($_, $bindir); } @progfiles);
|
||
map({ handle_file($_, $dbupdir); } @dbplfiles);
|
||
map({ handle_file($_, $dbupdir2); } @dbplfiles2);
|
||
|
||
sub handle_file {
|
||
my ($file, $dir) = @_;
|
locale/de/login | ||
---|---|---|
'Database Host' => 'Datenbankcomputer',
|
||
'Dataset' => 'Datenbank',
|
||
'Dataset upgrade' => 'Datenbankaktualisierung',
|
||
'Dependency loop detected:' => 'Schleife in den Abhängigkeiten entdeckt:',
|
||
'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
|
||
'Incorrect username or password!' => 'Ung?ltiger Benutzername oder falsches Passwort!',
|
||
'Licensed to' => 'Lizensiert f?r',
|
||
'Login' => 'Anmeldung',
|
||
'Login Name' => 'Benutzername',
|
||
'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
|
||
'Missing \'tag\' field.' => 'Fehlendes Feld \'tag\'.',
|
||
'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
|
||
'Password' => 'Passwort',
|
||
'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
|
||
'Unknown dependency \'%s\'.' => 'Unbekannte Abhängigkeit \'%s\'.',
|
||
'User' => 'Benutzer',
|
||
'Version' => 'Version',
|
||
'You are logged out!' => 'Auf Wiedersehen!',
|
locale/de/ustva | ||
---|---|---|
'Dauerfristverl?ngerung' => 'Dauerfristverl?ngerung',
|
||
'Dec' => 'Dez',
|
||
'December' => 'Dezember',
|
||
'Dependency loop detected:' => 'Schleife in den Abhängigkeiten entdeckt:',
|
||
'Description' => 'Beschreibung',
|
||
'ELSTER Export nach Taxbird' => 'ELSTER-Export nach Taxbird',
|
||
'ELSTER Export nach Winston' => 'ELSTER Export nach Winston',
|
||
'ELSTER-Steuernummer: ' => 'ELSTER-Steuernummer: ',
|
||
'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
|
||
'Fax' => 'Fax',
|
||
'Fax. : ' => 'Fax. : ',
|
||
'Fax.: ' => 'Fax.: ',
|
||
... | ... | |
'May' => 'Mai',
|
||
'May ' => 'Mai',
|
||
'Method' => 'Verfahren',
|
||
'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
|
||
'Missing \'tag\' field.' => 'Fehlendes Feld \'tag\'.',
|
||
'Missing Method!' => 'Fehlender Voranmeldungszeitraum',
|
||
'Missing Preferences: Outputroutine disabled' => 'Die Ausgabefunktionen sind wegen unzureichender Voreinstellungen deaktiviert!',
|
||
'Missing Tax Authoritys Preferences' => 'Fehlende Angaben zum Finanzamt!',
|
||
'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
|
||
'Name' => 'Name',
|
||
'Nov' => 'Nov',
|
||
'November' => 'November',
|
||
... | ... | |
'Tel. : ' => 'Tel. : ',
|
||
'Tel.: ' => 'Tel.: ',
|
||
'Telefon' => 'Telefon',
|
||
'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
|
||
'USTVA-Hint: Method' => 'Wenn Sie Ist-Versteuert sind, w?hlen Sie die Einnahmen-/?berschu?-Rechnung aus. Sind Sie Soll-Versteuert und bilanzverpflichtet, dann w?hlen Sie Bilanz aus.',
|
||
'USTVA-Hint: Tax Authoritys' => 'Bitte das Bundesland UND die Stadt bzw. den Einzugsbereich Ihres zust?ndigen Finanzamts ausw?hlen.',
|
||
'UStVA' => 'UStVA',
|
||
'UStVA als PDF-Dokument' => 'UStVa als PDF-Dokument',
|
||
'Unknown dependency \'%s\'.' => 'Unbekannte Abhängigkeit \'%s\'.',
|
||
'Vendor not on file!' => 'Lieferant ist nicht in der Datenbank!',
|
||
'Verfahren' => 'Verfahren',
|
||
'Verrechnung des Erstattungsbetrages erw?nscht (Zeile 71)' => 'Verrechnung des Erstattungsbetrages erw?nscht (Zeile 71)',
|
scripts/dbupgrade2_tool.pl | ||
---|---|---|
#!/usr/bin/perl
|
||
|
||
BEGIN {
|
||
if (! -d "bin" || ! -d "SL") {
|
||
print("This tool must be run from the Lx-Office ERP base directory.\n");
|
||
exit(1);
|
||
}
|
||
}
|
||
|
||
use DBI;
|
||
use Data::Dumper;
|
||
use Getopt::Long;
|
||
|
||
use SL::LXDebug;
|
||
|
||
$lxdebug = LXDebug->new();
|
||
|
||
use SL::Form;
|
||
use SL::DBUpgrade2;
|
||
|
||
#######
|
||
#######
|
||
#######
|
||
|
||
sub show_help {
|
||
print("dbupgrade2_tool.pl [--list] [--tree] [--rtree] [--graphviz]\n" .
|
||
" [--nodepds] [--help]\n");
|
||
}
|
||
|
||
sub calc_rev_depends {
|
||
map({ $_->{"rev_depends"} = []; } values(%{$controls}));
|
||
foreach my $control (values(%{$controls})) {
|
||
map({ push(@{$controls->{$_}{"rev_depends"}}, $control->{"tag"}) }
|
||
@{$control->{"depends"}});
|
||
}
|
||
}
|
||
|
||
sub dump_list {
|
||
my @sorted_controls = sort_dbupdate_controls($controls);
|
||
|
||
print("LIST VIEW\n\n");
|
||
print("number tag depth priority\n");
|
||
$i = 0;
|
||
foreach (@sorted_controls) {
|
||
print("$i $_->{tag} $_->{depth} $_->{priority}\n");
|
||
$i++;
|
||
}
|
||
|
||
print("\n");
|
||
}
|
||
|
||
sub dump_node {
|
||
my ($tag, $depth) = @_;
|
||
|
||
print(" " x $depth . $tag . "\n");
|
||
|
||
my $c = $controls->{$tag};
|
||
my $num = scalar(@{$c->{"depends"}});
|
||
for (my $i = 0; $i < $num; $i++) {
|
||
dump_node($c->{"depends"}[$i], $depth + 1);
|
||
}
|
||
}
|
||
|
||
sub dump_tree {
|
||
print("TREE VIEW\n\n");
|
||
|
||
calc_rev_depends();
|
||
|
||
my @sorted_controls = sort_dbupdate_controls($controls);
|
||
|
||
foreach my $control (@sorted_controls) {
|
||
dump_node($control->{"tag"}, "") unless (@{$control->{"rev_depends"}});
|
||
}
|
||
|
||
print("\n");
|
||
}
|
||
|
||
sub dump_node_reverse {
|
||
my ($tag, $depth) = @_;
|
||
|
||
print(" " x $depth . $tag . "\n");
|
||
|
||
my $c = $controls->{$tag};
|
||
my $num = scalar(@{$c->{"rev_depends"}});
|
||
for (my $i = 0; $i < $num; $i++) {
|
||
dump_node_reverse($c->{"rev_depends"}[$i], $depth + 1);
|
||
}
|
||
}
|
||
|
||
sub dump_tree_reverse {
|
||
print("REVERSE TREE VIEW\n\n");
|
||
|
||
calc_rev_depends();
|
||
|
||
my @sorted_controls = sort_dbupdate_controls($controls);
|
||
|
||
foreach my $control (@sorted_controls) {
|
||
last if ($control->{"depth"} > 1);
|
||
dump_node_reverse($control->{"tag"}, "");
|
||
}
|
||
|
||
print("\n");
|
||
}
|
||
|
||
sub dump_graphviz {
|
||
print("GRAPHVIZ POSTCRIPT\n\n");
|
||
print("Output will be written to db_dependencies.ps\n");
|
||
$dot = "|dot -Tps ";
|
||
open(OUT, "${dot}> db_dependencies.ps");
|
||
print(OUT
|
||
"digraph db_dependencies {\n" .
|
||
"node [shape=box];\n");
|
||
my %ranks;
|
||
foreach my $c (values(%{$controls})) {
|
||
$ranks{$c->{"depth"}} = [] unless ($ranks{$c->{"depth"}});
|
||
push(@{$ranks{$c->{"depth"}}}, $c->{"tag"});
|
||
}
|
||
foreach (sort(keys(%ranks))) {
|
||
print(OUT "{ rank = same; " .
|
||
join("", map({ '"' . $_ . '"; ' } @{$ranks{$_}})) .
|
||
" }\n");
|
||
}
|
||
foreach my $c (values(%{$controls})) {
|
||
print(OUT "$c->{tag};\n");
|
||
foreach my $d (@{$c->{"depends"}}) {
|
||
print(OUT "$c->{tag} -> $d;\n");
|
||
}
|
||
}
|
||
print(OUT "}\n");
|
||
close(OUT);
|
||
}
|
||
|
||
sub dump_nodeps {
|
||
calc_rev_depends();
|
||
|
||
print("SCRIPTS NO OTHER SCRIPTS DEPEND ON\n\n" .
|
||
join("\n",
|
||
map({ $_->{"tag"} }
|
||
grep({ !@{$_->{"rev_depends"}} }
|
||
values(%{$controls})))) .
|
||
"\n\n");
|
||
}
|
||
|
||
#######
|
||
#######
|
||
#######
|
||
|
||
eval { require "lx-erp.conf"; };
|
||
|
||
$form = Form->new();
|
||
$locale = Locale->new("de", "login");
|
||
|
||
#######
|
||
#######
|
||
#######
|
||
|
||
my ($opt_list, $opt_tree, $opt_rtree, $opt_nodeps, $opt_graphviz, $opt_help);
|
||
|
||
GetOptions("list" => \$opt_list,
|
||
"tree" => \$opt_tree,
|
||
"rtree" => \$opt_rtree,
|
||
"nodeps" => \$opt_nodeps,
|
||
"graphviz" => \$opt_graphviz,
|
||
"help" => \$opt_help,
|
||
);
|
||
|
||
if ($opt_help) {
|
||
show_help();
|
||
exit(0);
|
||
}
|
||
|
||
$controls = parse_dbupdate_controls($form, "Pg");
|
||
|
||
if ($opt_list) {
|
||
dump_list();
|
||
}
|
||
|
||
if ($opt_tree) {
|
||
dump_tree();
|
||
}
|
||
|
||
if ($opt_rtree) {
|
||
dump_tree_reverse();
|
||
}
|
||
|
||
if ($opt_graphviz) {
|
||
dump_graphviz();
|
||
}
|
||
|
||
if ($opt_nodeps) {
|
||
dump_nodeps();
|
||
}
|
sql/Pg-upgrade/Pg-upgrade-2.4.0.0-2.4.0.1.sql | ||
---|---|---|
ALTER TABLE language ADD COLUMN output_numberformat text;
|
||
ALTER TABLE language ADD COLUMN output_dateformat text;
|
||
ALTER TABLE language ADD COLUMN output_longdates boolean;
|
sql/Pg-upgrade/Pg-upgrade-2.4.0.1-2.4.0.2.sql | ||
---|---|---|
CREATE TABLE units_language (
|
||
unit varchar (20) NOT NULL,
|
||
language_id integer NOT NULL,
|
||
localized varchar (20),
|
||
localized_plural varchar (20),
|
||
|
||
FOREIGN KEY (unit) REFERENCES units (name),
|
||
FOREIGN KEY (language_id) REFERENCES language (id)
|
||
);
|
||
CREATE INDEX units_name_idx ON units (name);
|
||
CREATE INDEX units_language_unit_idx ON units_language (unit);
|
sql/Pg-upgrade/Pg-upgrade-2.4.0.2-2.4.0.3.sql | ||
---|---|---|
update tax set id=0 WHERE taxkey=0;
|
sql/Pg-upgrade2/README | ||
---|---|---|
Bitte lesen Sie die Datei doc/sql-upgrade-dateien.txt, bevor
|
||
Sie hier Dateien anlegen.
|
||
|
sql/Pg-upgrade2/language_output_formatting.sql | ||
---|---|---|
-- @tag: language_output_formatting
|
||
-- @description: Speichern des Ausgabeformates für Zahlen und Datumsangaben bei jeder Sprache.
|
||
-- @depends:
|
||
ALTER TABLE language ADD COLUMN output_numberformat text;
|
||
ALTER TABLE language ADD COLUMN output_dateformat text;
|
||
ALTER TABLE language ADD COLUMN output_longdates boolean;
|
sql/Pg-upgrade2/tax_id_if_taxkey_is_0.sql | ||
---|---|---|
-- @tag: tax_id_if_taxkey_is_0
|
||
-- @description: Aktualisierung der Spalte tax.id, wenn tax.taxkey = 0 ist.
|
||
-- @depends:
|
||
UPDATE tax SET id = 0 WHERE taxkey = 0;
|
sql/Pg-upgrade2/units_translations_and_singular_plural_distinction.sql | ||
---|---|---|
-- @tag: units_translations_and_singular_plural_distinction
|
||
-- @description: Für jede Einheit kann für jede Sprache eine Übersetzung sowie eine Unterscheidung zwischen Singular und Plural gespeichert werden.
|
||
-- @depends:
|
||
CREATE TABLE units_language (
|
||
unit varchar (20) NOT NULL,
|
||
language_id integer NOT NULL,
|
||
localized varchar (20),
|
||
localized_plural varchar (20),
|
||
|
||
FOREIGN KEY (unit) REFERENCES units (name),
|
||
FOREIGN KEY (language_id) REFERENCES language (id)
|
||
);
|
||
CREATE INDEX units_name_idx ON units (name);
|
||
CREATE INDEX units_language_unit_idx ON units_language (unit);
|
templates/webpages/dbupgrade/upgrade_message2_de.html | ||
---|---|---|
Führe <TMPL_VAR file ESCAPE=HTML> aus: <TMPL_VAR description ESCAPE=HTML><br>
|
templates/webpages/dbupgrade/upgrade_message2_master.html | ||
---|---|---|
<translate>Applying <TMPL_VAR file ESCAPE=HTML>:</translate> <TMPL_VAR description ESCAPE=HTML><br>
|
Auch abrufbar als: Unified diff
Neuer Datenbankupgrademechanismus: Die Upgradedateien im neuen Verzeichnis sql/Pg-upgrade2 enthalten Informationen über Abhängigkeiten, die von Lx-Office ausgewertet werden, um die Reihenfolge zu bestimmen, in der Updates angewandt werden. Wird nicht mehr über Versionsnummern geregelt.