You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@perl.apache.org by Stas Bekman <st...@stason.org> on 2004/03/24 03:51:12 UTC

[mp2] ModPerl::Util::parse_version

Any objects to this new util function? If you follow the discussion on p5p, we 
have no way but to provide our own function for multiple reasons. Besides, 
it's does exactly what most mp2 module authors will want, i.e.:

if (ModPerl::Util::parse_version("Apache::Request") > 2 &&
     eval { require Apache::Request }) {
     # use Apache::Request
}
else {
     # use something else
}

you don't need to check for defined, nor to force numerical context for cases 
like '2.03-dev'. it gives you a good number to use.

notice that 'use Apache::Request 2.0' doesn't work, because it may load an old 
mp1 version which is not binary compatible. and as it's in case of 
Apache::Status, we don't want to die if Apache::Request version wasn't 
satisfied, and CGI.pm is available.

Unless you have better ideas, I'll go ahead and commit this new function and 
use it in Apache::Status which is currently somewhat broken because of that.

--- /dev/null	1969-12-31 16:00:00.000000000 -0800
+++ xs/ModPerl/Util/Util_pm	2004-03-23 18:32:48.797050343 -0800
@@ -0,0 +1,62 @@
+use File::Spec ();
+
+# mp2 modules have to deal with situations where a binary incompatible
+# mp1 version of the same module is installed in the same
+# tree. therefore when checking for a certain version, one wants to
+# check the version of the module 'require()' will find without
+# loading that module. this function partially adopted from
+# ExtUtils::MM_Unix does just that. it returns the version number of
+
+# the first module that it finds, forcing numerical context, making
+# the return value suitable for immediate numerical comparison
+# operation. (i.e. 2.03-dev will be returned as 2.03,  0 will be
+# returned when the parsing has failed or a module wasn't found).
+sub parse_version {
+    my $name = shift;
+    die "no module name passed" unless $name;
+    my $file = File::Spec->catfile(split /::/, $name) . '.pm';
+    for my $dir (@INC) {
+        next if ref $dir; # skip code refs
+
+        my $pmfile = File::Spec->catfile($dir, $file);
+        next unless -r $pmfile;
+
+        open my $fh, $pmfile or die "can't open $pmfile: $!";
+
+        my $inpod = 0;
+        my $version;
+        while (<$fh>) {
+            $inpod = /^=(?!cut)/ ? 1 : /^=cut/ ? 0 : $inpod;
+            next if $inpod || /^\s*#/;
+
+            chomp;
+            next unless /([\$*])(([\w\:\']*)\bVERSION)\b.*\=/;
+            { local($1, $2); ($_ = $_) = /(.*)/; } # untaint
+            my $eval = qq{
+                package ModPerl::Util::_version;
+                no strict;
+
+                local $1$2;
+                \$$2=undef; do {
+                    $_
+                }; \$$2
+            };
+            no warnings;
+            $version = eval $eval;
+            warn "Could not eval '$eval' in $parsefile: $@" if $@;
+            last;
+        }
+
+        close $fh;
+
+        # avoid situations like "2.03-dev" and return a numerical
+        # version
+        if (defined $version) {
+            no warnings;
+            $version += 0; # force number
+            return $version;
+        }
+    }
+
+    return 0; # didn't find the file or the version number
+}

-- 
__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org


Re: [mp2] ModPerl::Util::parse_version

Posted by Stas Bekman <st...@stason.org>.
Geoffrey Young wrote:
> 
> Stas Bekman wrote:
> 
>>Any objects to this new util function? 
> 
> 
> not really.  but...
> 
> 
>>If you follow the discussion on
>>p5p, we have no way but to provide our own function for multiple
>>reasons. Besides, it's does exactly what most mp2 module authors will
>>want, i.e.:
>>
>>if (ModPerl::Util::parse_version("Apache::Request") > 2 &&
>>    eval { require Apache::Request }) {
>>    # use Apache::Request
>>}
>>else {
>>    # use something else
>>}
>>
>>you don't need to check for defined, nor to force numerical context for
>>cases like '2.03-dev'. it gives you a good number to use.
>>
>>notice that 'use Apache::Request 2.0' doesn't work, because it may load
>>an old mp1 version which is not binary compatible. 
> 
> 
> I think that a simple 'use' will suffice for the vast majority of users.  if
>  you try to 'use Apache::Request 2.0;' and you get the wrong version then
> something is wrong with your application setup - you've forgotten to load
> Apache2.pm or somesuch.  most people will indeed want it to fail, so
> requiring a the module and having it die when compared to the required
> version is DWIMmy.

This is almost 99% correct. The remaining problem is that when this wrong 
library gets loaded (and a particular request that triggered it aborts) and a 
user doesn't restart the server, he will see all kind of broken things.

>>and as it's in case
>>of Apache::Status, we don't want to die if Apache::Request version
>>wasn't satisfied, and CGI.pm is available.
> 
> 
> yes, I see that.  but it's probably a very rare case, substituting one
> module for another - you generally can't just do that in production code (at
> least you can't if you really value "production").  so, outside of
> substituting one module for another, I don't see this function being all
> that useful.
> 
> 
>>Unless you have better ideas, I'll go ahead and commit this new function
>>and use it in Apache::Status which is currently somewhat broken because
>>of that.
> 
> 
> p5p seemed to be interested in adding the functionality to version.pm or
> somesuch, so maybe wait and see how it plays out there before we end up
> maintaining our own version?

Yes, but p5p seems to be reluctant to make it working under -T (I'm not 
disagreeing with Hugo, just trying to find a solution that will work).

So, I agree that Apache::Status is unique. So what I'm going to do is to 
inline that function in Apache::Status, because I see no other solution at the 
moment - we get the test suite broken, when only mp1 version is installed (it 
fails to do the version check, but it's loaded nevertheless and this breaks 
other modules, e.g. Apache::compat). If we find other places where it's going 
to be useful, we can always expose it.

Thanks for the comments, Geoff!

__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org


Re: [mp2] ModPerl::Util::parse_version

Posted by Geoffrey Young <ge...@modperlcookbook.org>.

Stas Bekman wrote:
> Any objects to this new util function? 

not really.  but...

> If you follow the discussion on
> p5p, we have no way but to provide our own function for multiple
> reasons. Besides, it's does exactly what most mp2 module authors will
> want, i.e.:
> 
> if (ModPerl::Util::parse_version("Apache::Request") > 2 &&
>     eval { require Apache::Request }) {
>     # use Apache::Request
> }
> else {
>     # use something else
> }
> 
> you don't need to check for defined, nor to force numerical context for
> cases like '2.03-dev'. it gives you a good number to use.
> 
> notice that 'use Apache::Request 2.0' doesn't work, because it may load
> an old mp1 version which is not binary compatible. 

I think that a simple 'use' will suffice for the vast majority of users.  if
 you try to 'use Apache::Request 2.0;' and you get the wrong version then
something is wrong with your application setup - you've forgotten to load
Apache2.pm or somesuch.  most people will indeed want it to fail, so
requiring a the module and having it die when compared to the required
version is DWIMmy.

> and as it's in case
> of Apache::Status, we don't want to die if Apache::Request version
> wasn't satisfied, and CGI.pm is available.

yes, I see that.  but it's probably a very rare case, substituting one
module for another - you generally can't just do that in production code (at
least you can't if you really value "production").  so, outside of
substituting one module for another, I don't see this function being all
that useful.

> 
> Unless you have better ideas, I'll go ahead and commit this new function
> and use it in Apache::Status which is currently somewhat broken because
> of that.

p5p seemed to be interested in adding the functionality to version.pm or
somesuch, so maybe wait and see how it plays out there before we end up
maintaining our own version?

--Geoff


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org