melguin has asked for the wisdom of the Perl Monks concerning the following question:

Is there a function that just loads the called script without executing it? I've looked for answers to this question, but keep going in circles. I'm sure I'm just looking in the wrong places.

I am writing an uninstall script for someone else's install script. The install script contains several hashes which contain information that my script will need. At first I just copied the hashes into my script, but then got to thinking about how this would be a nightmare to upkeep both the installer and the uninstall should somethings change.

So, I started looking into just importing those hashes directly from the installer, but I can't find out how to do it. I looked at require, but that seems to run the script first and use seems to be just for modules.

I vaugely remember doing something like this a long while ago, but can't remember how I did it (or even if the circumstances would even apply since I can't modify the installer).

thanks as always.

Replies are listed 'Best First'.
Re: require without the exec
by benn (Vicar) on May 22, 2003 at 20:19 UTC
    From all sorts of perspectives, ( not *just* nice design principles :) ), I'd suggest you move the data fom the install script into a db / textfile / module / Data::Dumper'ed whatever, and then using it from both scripts - trying to include a whole bunch of code simply to retrieve some static data seems a bit overkill, not to say problematic...

    Cheers,
    Ben.

      Excellent points, and I agree. With all of the other install/modify scripts I wrote surrounding this one, I do use text files for the data that may change -- that way the person updating in the future doesn't have to know my code, just make a list of what packages they want installed and in which order.

      However, the big problem is that I can't modify code in the "other" installer that I need to write an uninstaller for--It would make my life easier if I could just rewrite it, though. Thus the need to grab from from it. Actually, half of the installer is hashes

        Sorry - I misunderstood the degree of control over the code you had. Surely though, if *somebody* is able to change the installer (and is likely to in the future), could some communication not happen between the two of you? If you wrote a patch for *their* code to read *your* datafile, would it be accepted? (Make it seem like it was their idea, but you're prepared to do all the work - always works for me {g}).

        Sorry too to suggest a 'social engineering' solution, but short of (as was suggested by skx) parsing the file, it's looking like your best hope :)

        Cheers,
        Ben.

        If you can't modify the installer, then the only option I see is to parse the install script, although this seems sort of ridiculous. It sounds like you can view the code of the installer, so parsing the code shouldn't be too difficult. Just be sure to do some sort of checking so you don't eval malicious code.
Re: require without the exec
by John M. Dlugosz (Monsignor) on May 22, 2003 at 22:05 UTC
    I don't think there is such a concept. If it's not executed, you won't see any values for the hashes you loaded!

    For a module, "loading" it will initialize these things and that's all, until you call something else inside it. But for a script, you want to have it execute the lines that set up your data structures, but then stop before doing the "main" code. That could be mixed in, and there is no general way to tell. However, the structure of your script might make it clear: in the simplest case, copy just the top N lines to a temp file and load that.

Re: require without the exec
by tcf22 (Priest) on May 22, 2003 at 20:33 UTC
    I'm not aware of anyway to do this through perl. Your best bet would be to use a data file. I did something similiar to this before and Data::Dumper came in handy.

    In the install script you could do something like this:
    use Data::Dumper; open(F, ">uninstall.dat") || die "Opening uninstall file failed: $!\n" +; print F Dumper \%hash; close(F);
    Then in the uninstaller just read in the file and eval it and $VAR1(or whatever you name the variable) will contain a reference to the original hash.
Re: require without the exec
by skx (Parson) on May 22, 2003 at 20:40 UTC

     You said you can't modify the installer; so I'll not suggest writing both to read the files from a configuration file... Although that's clearly the optimal solution.

     Is the installer sufficiently well formed that you could parse it manually, and extract the files from that?

     If not you might look at some of the sandboxing modules for evaling, but removing dangerous options from their reach - not a great solution but a possible area to explore.

    Steve
    ---
    steve.org.uk
Re: require without the exec
by broquaint (Abbot) on May 23, 2003 at 10:05 UTC
Re: require without the exec
by Bagarre (Sexton) on May 23, 2003 at 15:13 UTC
    It's not a technical solution but, why not have the install script build an uninstall config file?
Re: require without the exec
by ldapguru (Initiate) on May 23, 2003 at 15:35 UTC
    May be i'm wrong but, if you put '1;' as the last line in a perl module you prevent it from being executed?

      ... You probably are.
      See require for the why ...
      The file must return true as the last statement to indicate successful execution of any initialization code, so it's customary to end such a file with 1; unless you're sure it'll return true otherwise. But it's better just to put the 1;, in case you add more statements.

      Have a nice day
      All decision is left to your taste

Re: require without the exec
by TomDLux (Vicar) on May 23, 2003 at 23:19 UTC
    So half the install script is a hash. How about reading in the install script, isolating the section you want, and evaling that?
Re: require without the exec
by melguin (Pilgrim) on May 27, 2003 at 17:55 UTC
    Thanks for everyone's replies. I ended up just parsing the install file and grabbing the hash (it only ended up only being one). I needed.

    Here's the code that does it in case this can help out anyone else:

    my %SERVICE; open (INSTALL, "install.pl") or die "$!"; while (<INSTALL>) { if (/my\s+%SERVICE\s+=\s+\(\s*$/) { $read = 1; next; } # just in case there are some values on the first line if (/my\s+%SERVICE\s+=\s+\(\s*"([^"]+)"\s+=>\s+"([^"])\s*,/) { print "\t\"$1\"\t=> \"$2\",\n"; $SERVICE{$1} = $2; $read = 1; next; } if ($read) { # if there's something on the last line of the hash if (/"([^"]+)"\s+=>\s+"([^"])\s*\)\s*;/) { $service .= + $1; last; } # if there's not if (/([^\)]\));/) { $service .= $1; last; } # or if we're not on the last line grab the values if (/"([^"]+)"\s+=>\s+"([^"]+)"\s*,\s*$/) { $SERVICE{$ +1} = $2 } } } close INSTALL;
    Basically the hash is a list of services that get disabled in the /etc/rc.d directories. For example, here's one line:
    "/etc/rc2.d/S88sendmail" => "Sendmail",

    Again, thanks everyone.