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