Brad Fitzpatrick (bradfitz) wrote in lj_dev,
Brad Fitzpatrick
bradfitz
lj_dev

ljconfig-local.pl is stupid.

An exchange between avva and me, ending in the decision that ljconfig-local.pl is stupid and should die, to be replaced by ljlib-local.pl.

Brad writes:
I recently changed ljlib.pl's header from:

 require "$ENV{'LJHOME'}/cgi-bin/ljconfig.pl";
 require "$ENV{'LJHOME'}/cgi-bin/ljdefaults.pl";

to:

# determine how we're going to send mail
BEGIN {
    do "$ENV{'LJHOME'}/cgi-bin/ljconfig.pl";
    do "$ENV{'LJHOME'}/cgi-bin/ljdefaults.pl";

    $LJ::OPTMOD_NETSMTP = eval "use Net::SMTP (); 1;";
    if ($LJ::SMTP_SERVER) {
        die "Net::SMTP not installed\n" unless $LJ::OPTMOD_NETSMTP;
        MIME::Lite->send('smtp', $LJ::SMTP_SERVER, Timeout => 10);
    } else {
        MIME::Lite->send('sendmail', $LJ::SENDMAIL);
    }
}

but now, hooks are loaded in a web context (from BML, etc), but not from
command line programs which just source ljlib.pl, like synsuck, so synsuck
is segfaulting on synsuck, just like deadjournal.

do I not understand perl's BEGIN blocks and do statements?

what's invalidating %LJ::HOOKS?  :-/


Avva replies:
I toyed around with this a bit... seems LJ::HOOKS is never filled in.
When you "do ljconfig.pl" in BEGIN, eventually
it gets to ljcom.pl and its code. ljcom.pl gets compiled fine, but its
execution (all its initialisation statements) fails, so it never gets
to define the hooks. The reason they fail is that ljlib's BEGIN is
executed before the rest of ljlib.pl is even parsed, much less
compiled. Inside that BEGIN, all LJ:: functions haven't been defined
yet. The rest of the stuff works because ljconfig.pl and ljdefaults.pl
are just a bunch of assignments, they don't use LJ:: functions.

Why this works in web context? More complicated. The difference is
that in web context, everything begins with ljconfig.pl (require'd in
modperl.pl). Then it goes
ljconfig.pl->ljconfig-local.pl->ljcom.pl->paylib.pl->ljlib.pl ,
and the whole of ljlib.pl is compiled (while its invokation of
ljconfig.pl in BEGIN doesn't get to ljcom.pl the second time
because require's are forced by Perl to be non-reentrant, and while
ljlib.pl doesn't require ljconfig.pl, it do'es it, ljconfig.pl
require's ljconfig-local.pl ); after that execution continues in
ljcom.pl and everything goes through because ljlib.pl has been
compiled.

So it only works by accident, because of this incidental
ljcom.pl->paylib.pl->ljlib.pl connection. It's pretty silly that on
ljcom installations, require'ing ljconfig.pl pulls in ljlib.pl, but
on livejournal installations, that's not the case. This probably bits
people on their asses every now and then.


And then he replies again later....
Really, when you think about it, ljconfig-local.pl is not the right place to
pull in ljcom.pl and other site-specific libraries. Rather, this
should be done in a new ljlib-local.pl (and we don't need
ljconfig-local.pl at all then, since ljconfig.pl is supposed to be
customised directly anyway). Here's how it should be working, I think:

a) no ljconfig-local.pl . This means that require'ing ljconfig.pl
doesn't execute anything heavy (as it does now), but only defines
lots of constants from ljconfig.pl and ljdefaults.pl .

b) ljlib-local.pl comes from ljcom CVS, require's ljcom.pl . Perhaps
it should also require paylib.pl separately, rather than from
ljcom.pl, not sure if it matters.

c) Now you can "do" ljconfig.pl,ljdefaults.pl in ljlib.pl in a BEGIN
block without problems.

d) in ljlib.pl at the beginning, you require ljlib-local.pl if there
is one; or if you prefer, you "do" it in a BEGIN block, but put it at
the end of ljlib.pl, that'll work too because LJ:: functions have been
compiled by then and ljcom's initialisation will work.

Thoughts?
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 1 comment