[devel] autodeps

Mikhail Zabaluev =?iso-8859-1?q?mookid_=CE=C1_sigent=2Eru?=
Сб Ноя 25 00:07:46 MSK 2000


Привет.

Обнаружил, в чем проблема с 'AutoReqProv: perl' в rpm. Скрипт
find-provides слишком полагается на суждение программы file о том, что
есть perl script. Та, на самом деле, почти никогда не скажет такого о 
модуле, который не начинается со строки типа '#!/usr/bin/perl'.
file-3.33-1mdk вообще считает многие модули какими-то файлами для
palmtop'а Newton, даже не текстовыми! Пришлось отучать.

Прилагаю патч для find-{provides,requires} и снова perl.prov - там нужно
было добавить содержимое RPM_BUILD_ROOT ко всем путям поиска.

Следует заметить, что скриптам perl.prov и perl.req лучше давать весь
список файлов зараз - так _намного_ быстрее.

Еще есть предложения:
- добавить еще один псевдоним для значения по умолчанию Auto{Req,Prov} -
  'default', чтобы можно было писать 'AutoReqProv: default, perl'
  или 'AutoReqProv: default, noshell';
- реализовать подстановку переменной окружения RPM_PERL_LIB_PATH для
  perl.prov из макроса.

-- 
Stay tuned,
  MhZ                                    mailto:mookid на sigent.ru
-----------
Mr. Cole's Axiom:
	The sum of the intelligence on the planet is a constant;
	the population is growing.
----------- следующая часть -----------
--- find-provides.orig	Fri Nov 24 18:51:28 2000
+++ find-provides	Fri Nov 24 22:28:31 2000
@@ -91,7 +91,7 @@
 {
 	local f="$1"
 	local t="$2"
-	if [ -z "${t/$f: perl script text*/}" ]; then
+	if [ -z "${t/$f: perl script text*/}" -o -z "${f/*.p[lmh]/}" ]; then
 		if [ -n "$FIND_PERL" ]; then
 			/usr/lib/rpm/perl.prov "$f"
 		fi
@@ -129,7 +129,7 @@
 
 while IFS= read -r f; do
 	if t="$(file -L "$f")"; then
-		if [ -z "${t/$f: * script text*/}" ]; then
+		if [ -z "${t/$f: * text*/}" ]; then
 			FOUND_PROVS="$FOUND_PROVS
 $(FindScriptProvs "$f" "$t")"
 		elif [ -z "${t/$f: * shared object*/}" ]; then
--- find-requires.orig	Fri Nov 24 18:51:39 2000
+++ find-requires	Fri Nov 24 22:28:21 2000
@@ -115,7 +115,7 @@
 		if [ -n "$FIND_SHELL" ]; then
 			/usr/lib/rpm/shell.req "$f"
 		fi
-	elif [ -z "${t/$f: perl script text*/}" ]; then
+	elif [ -z "${t/$f: perl script text*/}" -o -z "${f/*.p[lmh]/}" ]; then
 		if [ -n "$FIND_PERL" ]; then
 			/usr/lib/rpm/perl.req "$f"
 		fi
@@ -164,7 +164,7 @@
 
 while IFS= read -r f; do
 	t="$(file "$f")"
-	if [ -z "${t/$f: * script text*/}" ]; then
+	if [ -z "${t/$f: * text*/}" ]; then
 		FOUND_REQS="$FOUND_REQS
 $(FindScriptReqs "$f" "$t")"
 	elif [ -z "${t/$f: * executable*/}" ]; then
----------- следующая часть -----------
#!/usr/bin/perl

# RPM (and it's source code) is covered under two separate licenses.

# The entire code base may be distributed under the terms of the GNU
# General Public License (GPL), which appears immediately below.
# Alternatively, all of the source code in the lib subdirectory of the
# RPM source code distribution as well as any code derived from that
# code may instead be distributed under the GNU Library General Public
# License (LGPL), at the choice of the distributor. The complete text
# of the LGPL appears at the bottom of this file.

# This alternative is allowed to enable applications to be linked
# against the RPM library (commonly called librpm) without forcing
# such applications to be distributed under the GPL.

# Any questions regarding the licensing of RPM should be addressed to
# Erik Troan <ewt на redhat.com>.

# a simple script to print the proper name for perl libraries.

# To save development time I do not parse the perl grammmar but
# instead just lex it looking for what I want.  I take special care to
# ignore comments and pod's.

# it would be much better if perl could tell us the proper name of a
# given script.

# The filenames to scan are either passed on the command line or if
# that is empty they are passed via stdin.

# If there are lines in the file which match the pattern
#      (m/^\s*\$VERSION\s*=\s+/)
# then these are taken to be the version numbers of the modules.

# If there are strings in the file which match the pattern
#     m/^\s*\$RPM_Provides\s*=\s*["'](.*)['"]/i
# then these are treated as additional names which are provided by the
# file and are printed as well.

# The RPM_PERL_LIB_PATH environment variable, if set, must contain the list of
# absolute paths, separated by colons, spaces or commas. These paths are
# considered as library paths used to determine relative names of provided
# perl files. If RPM_PERL_LIB_PATH is not set, paths from @INC Perl variable
# are used instead.

# by Ken Estes Mail.com kestes на staff.mail.com
# modified by Mikhail Zabaluev <mookid на mu.ru>

require v5.6.0;

use Safe;

use strict;

use vars qw(%provide @perl_inc);


# obtain the list of library directories. If not provided, use @INC

if (exists $ENV{RPM_PERL_LIB_PATH}) {
  @perl_inc = split(/[:,\s]+/, $ENV{RPM_PERL_LIB_PATH});
}
else {
  @perl_inc = grep { m|^/| } @INC;
}

# Sort @perl_inc descending by length to search for longest prefix rapidly.

@perl_inc = sort { length($b) <=> length($a) } @perl_inc;

# Prepend $RPM_BUILD_ROOT to paths.

my $buildroot = $ENV{RPM_BUILD_ROOT};
@perl_inc = map { "${buildroot}$_" } @perl_inc;

# process files

if (@ARGV) {
  foreach (@ARGV) {
    process_file($_);
  }
} else {

  # notice we are passed a list of filenames NOT as common in unix the
  # contents of the file.

  foreach (<>) {
    process_file($_);
  }
}

# print out sorted results

foreach my $module (sort keys %provide) {
  my $version = $provide{$module};
  if (length($version) == 0) {
    print "perl($module)\n";
  } else {
    print "perl($module) = $version\n";
    if ($version =~ /^1:(.*)/) {

      # provide an additional epoch 0 version converted using Perl's rules

      my $fpver = 0;
      my $ratio = 1;
      my @series = split(/\./, $1);
      for (@series) {
	$fpver += $_ * $ratio;
	$ratio *= 0.001;
      }
      my $fdigits = $#series * 3;
      printf("perl($module) = 0:%.${fdigits}f\n", $fpver);
    }
  }
}

exit 0;



sub process_file {

  my ($file) = @_;
  chomp $file;

  # find the longest matching prefix among Perl library search directories

  my $prefix = '';
  foreach (@perl_inc) {
    if (substr($file, 0, length($_)) eq $_) {
      $prefix = $_;
      last;
    }
  }

  return if $prefix eq '';

  # get path to the module file without prefix

  my $module_file = substr($file, length($prefix));
  $module_file =~ s{^/}{};

  $provide{$module_file} = undef;

  return if $module_file !~ /\.pm$/;

  # try to extract version number for this package

  open(FILE, "<$file")||
    die("$0: Could not open file: '$file' : $!\n");

  my $inpackage = 0;

  while (<FILE>) {
    
    # skip the documentation

    # we should not need to have item in this if statement (it
    # properly belongs in the over/back section) but people do not
    # read the perldoc.

    if ((m/^=(head[12]|pod|over|item|for|begin)/) .. (m/^=(cut)/)) {
      next;
    }
    
    # skip the data section
    if (m/^__(DATA|END)__$/) {
      last;
    }

    # not everyone puts the package name of the file as the first
    # package name so we browse through all namespaces

    if (m/^\s*package\s+([\w:']+)\s*;/) {
      $inpackage =  (module_filename($1) eq $module_file)? 1 : 0;
      next;
    }

    # after we found the package name take the first assignment to
    # $VERSION as the version number. Exporter requires that the
    # variable be called VERSION so we are safe.

    if ($inpackage &&
	s/^([\s(]*)(our\s*)?\$VERSION\s*=/$1\$VERSION =/) {
      $provide{$module_file} = extract_version($_);
      next;
    }

    # also consider version initializations with explicit package specification

    if (s/^([\s(]*)(our\s*)?\$([\w:']+)::VERSION\s*=/$1\$VERSION =/) {
      if (module_filename($3) eq $module_file) {
	$provide{$module_file} = extract_version($_);
      }
      next;
    }

    # Each keyword can appear multiple times.  Don't
    #  bother with datastructures to store these strings,
    #  if we need to print it print it now.
	
    if ( m/^\s*\$RPM_Provides\s*=\s*["'](.*)['"]/i) {
      foreach (split(/\s+/, $1)) {
	print "$_\n";
      }
    }

  }

  close(FILE)||
    die("$0: Could not close file: '$file' : $!\n");

  return ;
}


# module_filename($name) -
# converts module name to relative file path

sub module_filename {
  my $name = shift;
  $name =~ s{::|'}{/}g;
  return $name . '.pm';
}


# extract_version - 
# this subroutine tries to evaluate line containing assignment to $VERSION
# in order to achieve version number

sub extract_version {

  my $line = shift;

  # Try to evaluate the assignment to get the value of $VERSION.
  # It is usually computed without using data external to the expression,
  # so we would have no problems.

  local $SIG{__WARN__} = sub { };

  my $safe = new Safe;
  $safe->permit_only(qw(:base_core :base_mem :base_loop :base_orig entereval));
  my $version = $safe->reval("$line; \$VERSION;");

  return undef if $@ || length($version) == 0;

  if ($version =~ s/^\s*(\d[\d_]*(\.[\d_]*)?|\.[\d_]+)/$1/) {

    # plain old numeric version

    return '0:' . $version;
  }
  else {

    # Supposedly, a new style version evaluated as a string constant.
    # Return an epoch 1 version

    return sprintf('1:%vd', $version);
  }

  return undef;
}


Подробная информация о списке рассылки Devel