root/trunk/bin/upgrading/texttool.pl @ 1005

Revision 1005, 12.0 KB (checked in by bradfitz, 11 years ago)

more lang/text work

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/usr/bin/perl
2#
3# This program deals with inserting/extracting text/language data
4# from the database.
5#
6
7use strict;
8use Getopt::Long;
9
10my $opt_help = 0;
11my $opt_local_lang;
12exit 1 unless
13GetOptions(
14           "help" => \$opt_help,
15           "local-lang=s" => \$opt_local_lang,
16           );
17
18my $mode = shift @ARGV;
19
20help() if $opt_help or not defined $mode;
21
22sub help
23{
24    die "Usage: texttool.pl <command>
25
26Where 'command' is one of:
27  popstruct    Populate lang data from text[-local].dat into db
28  poptext      Populate text from en.dat, etc into database
29  dumptext     Dump lang text based on text[-local].dat information
30  check        Check validity of text[-local].dat files
31  wipedb       Remove all language/text data from database.
32  newitems     Search files in htdocs, cgi-bin, & bin and insert
33               necessary text item codes in database.
34
35               Optionally:
36                  --local-lang=..  If given, works on local site files too
37
38";
39}
40
41## make sure $LJHOME is set so we can load & run everything
42unless (-d $ENV{'LJHOME'}) {
43    die "LJHOME environment variable is not set, or is not a directory.\n".
44        "You must fix this before you can run this database update script.";
45}
46require "$ENV{'LJHOME'}/cgi-bin/ljlib.pl";
47
48my %dom_id;     # number -> {}
49my %dom_code;   # name   -> {}
50my %lang_id;    # number -> {}
51my %lang_code;  # name   -> {}
52my @lang_domains;
53
54my $set = sub {
55    my ($hash, $key, $val, $errmsg) = @_;
56    die "$errmsg$key\n" if exists $hash->{$key};
57    $hash->{$key} = $val;
58};
59
60foreach my $scope ("general", "local")
61{
62    my $file = $scope eq "general" ? "text.dat" : "text-local.dat";
63    my $ffile = "$ENV{'LJHOME'}/bin/upgrading/$file";
64    unless (-e $ffile) {
65        next if $scope eq "local";
66        die "$file file not found; odd: did you delete it?\n";
67    }
68    open (F, $ffile) or die "Can't open file: $file: $!\n";
69    while (<F>) {
70        s/\s+$//; s/^\#.+//;
71        next unless /\S/;
72        my @vals = split(/:/, $_);
73        my $what = shift @vals;
74
75        # language declaration
76        if ($what eq "lang") {
77            my $lang = {
78                'scope'  => $scope,
79                'lnid'   => $vals[0],
80                'lncode' => $vals[1],
81                'lnname' => $vals[2],
82                'parentlnid' => 0,   # default.  changed later.
83                'parenttype' => 'diff',
84            };
85            $lang->{'parenttype'} = $vals[3] if defined $vals[3];
86            if (defined $vals[4]) {
87                unless (exists $lang_code{$vals[4]}) {
88                    die "Can't declare language $lang->{'lncode'} with missing parent language $vals[4].\n";
89                }
90                $lang->{'parentlnid'} = $lang_code{$vals[4]}->{'lnid'};
91            }
92            $set->(\%lang_id,   $lang->{'lnid'},   $lang, "Language already defined with ID: ");
93            $set->(\%lang_code, $lang->{'lncode'}, $lang, "Language already defined with code: ");
94        }
95
96        # domain declaration
97        if ($what eq "domain") {
98            my $dcode = $vals[1];
99            my ($type, $args) = split(m!/!, $dcode);
100            my $dom = {
101                'scope' => $scope,
102                'dmid' => $vals[0],
103                'type' => $type,
104                'args' => $args || "",
105            };
106            $set->(\%dom_id,   $dom->{'dmid'}, $dom, "Domain already defined with ID: ");
107            $set->(\%dom_code, $dcode, $dom, "Domain already defined with parameters: ");
108        }
109
110        # langdomain declaration
111        if ($what eq "langdomain") {
112            my $ld = {
113                'lnid' =>
114                    (exists $lang_code{$vals[0]} ? $lang_code{$vals[0]}->{'lnid'} :
115                     die "Undefined language: $vals[0]\n"),
116                'dmid' =>
117                    (exists $dom_code{$vals[1]} ? $dom_code{$vals[1]}->{'dmid'} :
118                     die "Undefined domain: $vals[1]\n"),
119                'dmmaster' => $vals[2] ? "1" : "0",
120                };
121            push @lang_domains, $ld;
122        }
123    }
124    close F;
125}
126
127if ($mode eq "check") {
128    print "all good.\n";
129    exit 0;
130}
131
132## make sure we can connect
133my $dbh = LJ::get_dbh("master");
134my $sth;
135unless ($dbh) {
136    die "Can't connect to the database.\n";
137}
138
139popstruct() if $mode eq "popstruct";
140poptext() if $mode eq "poptext";
141dumptext() if $mode eq "dumptext";
142popstruct() if $mode eq "dump";
143newitems() if $mode eq "newitems";
144wipedb() if $mode eq "wipedb";
145help();
146
147sub wipedb
148{
149    $dbh->do("DELETE FROM ml_$_")
150        foreach (qw(domains items langdomains langs latest text));
151    exit 0;                 
152}
153
154sub popstruct
155{
156    foreach my $l (values %lang_id) {
157        print "Inserting language: $l->{'lnname'}\n";
158        $dbh->do("INSERT INTO ml_langs (lnid, lncode, lnname, parenttype, parentlnid) ".
159                 "VALUES (" . join(",", map { $dbh->quote($l->{$_}) } qw(lnid lncode lnname parenttype parentlnid)) . ")");
160        die "Error: " . $dbh->errstr if $dbh->err;
161    }
162
163    foreach my $d (values %dom_id) {
164        print "Inserting domain: $d->{'type'}\[$d->{'args'}\]\n";
165        $dbh->do("INSERT INTO ml_domains (dmid, type, args) ".
166                 "VALUES (" . join(",", map { $dbh->quote($d->{$_}) } qw(dmid type args)) . ")");
167        die "Error: " . $dbh->errstr if $dbh->err;
168    }
169
170    print "Inserting language domains ...\n";
171    foreach my $ld (@lang_domains) {
172        $dbh->do("INSERT IGNORE INTO ml_langdomains (lnid, dmid, dmmaster) VALUES ".
173                 "(" . join(",", map { $dbh->quote($ld->{$_}) } qw(lnid dmid dmmaster)) . ")");
174    }
175
176    print "All done.\n";
177    exit 0;
178}
179
180sub poptext
181{
182    foreach my $lang (keys %lang_code)
183    {
184        print "$lang\n";
185        my $l = $lang_code{$lang};
186        open (D, "$ENV{'LJHOME'}/bin/upgrading/${lang}.dat")
187            or die "Can't find $lang.dat\n";
188        my $lnum = 0;
189        my ($code, $text);
190        while (my $line = <D>) {
191            $lnum++;
192            if ($line =~ /^(\S+?)=(.*)/) {
193                ($code, $text) = ($1, $2);
194            } elsif ($line =~ /^(\S+?)\<\<\s*$/) {
195                ($code, $text) = ($1, "");
196                while (<D>) {
197                    last if $_ eq ".\n";
198                    s/^\.//;
199                    $text .= $_;
200                }
201            } elsif ($line =~ /\S/) {
202                die "$lang.dat:$lnum: Bogus format.\n";
203            }
204
205            my $qcode = $dbh->quote($code);
206            my $exists = $dbh->selectrow_array("SELECT COUNT(*) FROM ml_latest l, ml_items i ".
207                                               "WHERE l.dmid=1 AND i.dmid AND i.itcode=$qcode AND ".
208                                               "i.itid=l.itid AND l.lnid=$l->{'lnid'}");
209            if (! $exists) {
210                print " adding: $code = ";
211                my $res = LJ::Lang::set_text($dbh, 1, $lang, $code, $text);
212                print "$res\n";
213            }
214        }
215        close D;
216    }
217    exit 0;
218}
219
220sub dumptext
221{
222    foreach my $lang (keys %lang_code)
223    {
224        print "$lang\n";
225        my $l = $lang_code{$lang};
226        open (D, ">$ENV{'LJHOME'}/bin/upgrading/${lang}.dat")
227            or die "Can't open $lang.dat\n";
228        my $sth = $dbh->prepare("SELECT i.itcode, t.text FROM ".
229                                "ml_items i, ml_latest l, ml_text t ".
230                                "WHERE l.lnid=$l->{'lnid'} AND l.dmid=1 ".
231                                "AND i.dmid=1 AND l.itid=i.itid AND ".
232                                "t.dmid=1 AND t.txtid=l.txtid AND ".
233                                # only export mappings that aren't inherited:
234                                "t.lnid=$l->{'lnid'} ".
235                                "ORDER BY i.itcode");
236        $sth->execute;
237        while (my ($itcode, $text) = $sth->fetchrow_array) {
238            print "$itcode: $text\n";
239        }
240        close D;
241    }
242    exit 1;
243}
244
245sub newitems
246{
247    my $top = $ENV{'LJHOME'};
248    my @files;
249    push @files, qw(htdocs cgi-bin bin);
250    my %items;  # $scope -> $key -> 1;
251    print "Searching htdocs/cgi-bin/bin for referenced text codes...\n";
252    while (@files)
253    {
254        my $file = shift @files;
255        my $ffile = "$top/$file";
256        next unless -e $ffile;
257        if (-d $ffile) {
258            opendir (MD, $ffile) or die "Can't open $file";
259            while (my $f = readdir(MD)) {
260                next if $f eq "." || $f eq ".." ||
261                    $f =~ /^\.\#/ || $f =~ /(\.png|\.gif|~|\#)$/;
262                unshift @files, "$file/$f";
263            }
264            closedir MD;
265        }
266        if (-f $ffile) {
267            my $scope = "local";
268            $scope = "general" if -e "$top/cvs/livejournal/$file";
269
270            open (F, $ffile) or die "Can't open $file";
271            my $line = 0;
272            while (<F>) {
273                $line++;
274                while (/BML::ml\([\"\'](.+?)[\"\']/g) {
275                    $items{$scope}->{$1} = 1;
276                }
277                while (/\(=_ML\s+(.+?)\s+_ML=\)/g) {
278                    my $code = $1;
279                    if ($code =~ /^\./ && $file =~ m!^htdocs/!) {
280                        $code = "$file$code";
281                        $code =~ s!^htdocs!!;
282                    }
283                    $items{$scope}->{$code} = 1;
284                }
285            }
286            close F;
287        }
288    }
289
290    printf("  %d general and %d local found.\n",
291           scalar keys %{$items{'general'}},
292           scalar keys %{$items{'local'}});
293
294    my $register_code = sub
295    {
296        my $it = shift;
297        my $qcode = $dbh->quote($it);
298        $dbh->do("INSERT INTO ml_items (dmid, itid, itcode) ".
299                 "VALUES (1, NULL, $qcode)");
300        my $itid;
301        if ($dbh->err) {
302            $itid = $dbh->selectrow_array("SELECT itid FROM ml_items WHERE ".
303                                          "dmid=1 AND itcode=$qcode");
304        } else {
305            $itid = $dbh->{'mysql_insertid'};
306        }
307        unless ($itid) { die "Couldn't register code: $it\n"; }
308        return $itid;
309    };
310
311    my $set_text = sub
312    {
313        my ($itid, $lnid, $text) = @_;
314        my $qbogustext = $dbh->quote($text);
315        $dbh->do("INSERT INTO ml_text (dmid, txtid, lnid, itid, text, userid) VALUES ".
316                 "(1, NULL, $lnid, $itid, $qbogustext, 0)");
317        my $txtid = $dbh->{'mysql_insertid'};
318        unless ($txtid) { die "Couldn't register bogus text: $text\n"; }
319        $dbh->do("INSERT INTO ml_latest (lnid, dmid, itid, chgtime, txtid, version) VALUES ".
320                 "($lnid, 1, $itid, '0000-00-00', $txtid, 0)");
321    };
322
323    # [ General ]
324    my %e_general;  # code -> 1
325    print "Checking which general items already exist in database...\n";
326    my $sth = $dbh->prepare("SELECT i.itcode FROM ml_items i, ml_latest l WHERE ".
327                            "l.dmid=1 AND l.lnid=1 AND i.dmid=1 AND i.itid=l.itid");
328    $sth->execute;
329    while (my $it = $sth->fetchrow_array) { $e_general{$it} = 1; }
330    printf("  %d found\n", scalar keys %e_general);
331    foreach my $it (keys %{$items{'general'}}) {
332        next if exists $e_general{$it};
333        my $itid = $register_code->($it);
334        print "Added general: $it ($itid)\n";
335        $set_text->($itid, 1, "[no text: $it]");
336    }
337
338    if ($opt_local_lang) {
339        my $ll = $lang_code{$opt_local_lang};
340        die "Bogus --local-lang argument\n" unless $ll;
341        die "Local-lang '$ll->{'lncode'}' parent isn't 'en'\n"
342            unless $ll->{'parentlnid'} == 1;
343        print "Checking which local items already exist in database...\n";
344
345        my %e_local;
346        $sth = $dbh->prepare("SELECT i.itcode FROM ml_items i, ml_latest l WHERE ".
347                             "l.dmid=1 AND l.lnid=$ll->{'lnid'} AND i.dmid=1 AND i.itid=l.itid");
348        $sth->execute;
349        while (my $it = $sth->fetchrow_array) { $e_local{$it} = 1; }
350        printf("  %d found\n", scalar keys %e_local);
351        foreach my $it (keys %{$items{'local'}}) {
352            next if exists $e_general{$it};
353            next if exists $e_local{$it};
354            my $itid = $register_code->($it);
355            print "Added local: $it ($itid)\n";
356            $set_text->($itid, $ll->{'lnid'}, "[no text: $it]");
357        }
358    }
359   
360    #use Data::Dumper;
361    #print Dumper(\%items);
362
363    exit 0;
364}
Note: See TracBrowser for help on using the browser.