Blame template/bin/perl.req

Packit 745a47
#!/usr/bin/perl
Packit 745a47
Packit 745a47
# This is free software.  You may redistribute copies of it under the terms of
Packit 745a47
# the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.
Packit 745a47
# There is NO WARRANTY, to the extent permitted by law.
Packit 745a47
Packit 745a47
# This script was originally written by Ken Estes Mail.com
Packit 745a47
# kestes@staff.mail.com
Packit 745a47
Packit 745a47
# a simple script used to generate dependencies of Perl modules and scripts.
Packit 745a47
Packit 745a47
# It does not parse the perl grammar but instead just lex it looking for
Packit 745a47
# what we want. It takes special care to ignore comments and pod's.
Packit 745a47
Packit 745a47
# The filenames to scan are either passed on the command line or if
Packit 745a47
# that is empty they are passed via stdin.
Packit 745a47
Packit 745a47
# If there are strings in the file which match the pattern
Packit 745a47
#     m/^\s*\$RPM_Requires\s*=\s*["'](.*)['"]/i
Packit 745a47
# then these are treated as additional names which are required by the
Packit 745a47
# file and are printed as well.
Packit 745a47
Packit 745a47
my $perl_ns = "__PERL_NS__";
Packit 745a47
Packit 745a47
$HAVE_VERSION = 0;
Packit 745a47
eval { require version; $HAVE_VERSION = 1; };
Packit 745a47
use Fedora::VSP ();
Packit 745a47
Packit Service 74cec8
use File::Basename;
Packit Service 74cec8
my $dir = dirname($0);
Packit Service 74cec8
$HAVE_PROV = 0;
Packit Service 74cec8
if ( -e "$dir/perl.prov" ) {
Packit Service 74cec8
  $HAVE_PROV = 1;
Packit Service 74cec8
  $prov_script = "$dir/perl.prov";
Packit Service 74cec8
}
Packit 745a47
Packit 745a47
if ("@ARGV") {
Packit Service 74cec8
  foreach my $file (@ARGV) {
Packit Service 74cec8
    process_file($file);
Packit Service 74cec8
    process_file_provides($file);
Packit Service 74cec8
    compute_global_requires();
Packit 745a47
  }
Packit 745a47
} else {
Packit 745a47
Packit 745a47
  # notice we are passed a list of filenames NOT as common in unix the
Packit 745a47
  # contents of the file.
Packit 745a47
Packit Service 74cec8
  foreach my $file (<>) {
Packit Service 74cec8
    process_file($file);
Packit Service 74cec8
    process_file_provides($file);
Packit Service 74cec8
    compute_global_requires();
Packit 745a47
  }
Packit 745a47
}
Packit 745a47
Packit 745a47
Packit 745a47
foreach $perlver (sort keys %perlreq) {
Packit 745a47
  print "$perl_ns(:VERSION) >= $perlver\n";
Packit 745a47
}
Packit Service 74cec8
Packit Service 74cec8
foreach my $module (sort keys %global_require) {
Packit Service 74cec8
  if (length($global_require{$module}) == 0) {
Packit 745a47
    print "$perl_ns($module)\n";
Packit 745a47
  } else {
Packit 745a47
Packit 745a47
    # I am not using rpm3.0 so I do not want spaces around my
Packit 745a47
    # operators. Also I will need to change the processing of the
Packit 745a47
    # $RPM_* variable when I upgrade.
Packit 745a47
Packit Service 74cec8
    print "$perl_ns($module) >= $global_require{$module}\n";
Packit 745a47
  }
Packit 745a47
}
Packit 745a47
Packit 745a47
exit 0;
Packit 745a47
Packit Service 74cec8
sub compute_global_requires {
Packit Service 74cec8
 
Packit Service 74cec8
# restrict require_removable to all non provided by the file
Packit Service 74cec8
  foreach my $moduler (sort keys %require_removable) {
Packit Service 74cec8
    if (exists $provide{$moduler} && length($require_removable{$moduler}) == 0) {
Packit Service 74cec8
      $require_removable = delete $require_removable{$moduler};
Packit Service 74cec8
    } 
Packit Service 74cec8
  }
Packit Service 74cec8
# store requires to global_requires
Packit Service 74cec8
  foreach my $module (sort keys %require) {
Packit Service 74cec8
    my $oldver = $global_require{$module};
Packit Service 74cec8
    my $newver = $require{$module};
Packit Service 74cec8
    if ($oldver) {
Packit Service 74cec8
      $global_require{$module} = $newver
Packit Service 74cec8
        if ($HAVE_VERSION && $newver && version->new($oldver) < $newver);
Packit Service 74cec8
    } else {
Packit Service 74cec8
      $global_require{$module} = $newver;
Packit Service 74cec8
    }
Packit Service 74cec8
  }
Packit 745a47
Packit Service 74cec8
# store requires_removable to global_requires
Packit Service 74cec8
  foreach my $module (sort keys %require_removable) {
Packit Service 74cec8
    my $oldver = $global_require{$module};
Packit Service 74cec8
    my $newver = $require_removable{$module};
Packit Service 74cec8
    if ($oldver) {
Packit Service 74cec8
      $global_require{$module} = $newver
Packit Service 74cec8
        if ($HAVE_VERSION && $newver && version->new($oldver) < $newver);
Packit Service 74cec8
    } else {
Packit Service 74cec8
      $global_require{$module} = $newver;
Packit Service 74cec8
    }
Packit Service 74cec8
  }
Packit Service 74cec8
# remove all local requires and provides
Packit Service 74cec8
  undef %require;
Packit Service 74cec8
  undef %require_removable;
Packit Service 74cec8
  undef %provide;
Packit Service 74cec8
}
Packit 745a47
Packit 745a47
sub add_require {
Packit 745a47
  my ($module, $newver) = @_;
Packit 745a47
Packit 745a47
  # __EXAMPLE__ is not valid requirement
Packit 745a47
  return if ($module =~ m/^__[A-Z]+__$/o);
Packit 745a47
Packit 745a47
  # To prevent that module does not end with '::'
Packit 745a47
  # Example:  use base Object::Event::;
Packit 745a47
  $module =~ s/::$//;
Packit 745a47
Packit 745a47
  my $oldver = $require{$module};
Packit 745a47
  if ($oldver) {
Packit 745a47
    $require{$module} = $newver
Packit 745a47
      if ($HAVE_VERSION && $newver && version->new($oldver) < $newver);
Packit 745a47
  }
Packit 745a47
  else {
Packit 745a47
    $require{$module} = $newver;
Packit 745a47
  }
Packit 745a47
}
Packit 745a47
Packit Service 74cec8
sub add_require_removable {
Packit Service 74cec8
  my ($module, $newver) = @_;
Packit Service 74cec8
Packit Service 74cec8
  # __EXAMPLE__ is not valid requirement
Packit Service 74cec8
  return if ($module =~ m/^__[A-Z]+__$/o);
Packit Service 74cec8
Packit Service 74cec8
  # To prevent that module does not end with '::'
Packit Service 74cec8
  # Example:  use base Object::Event::;
Packit Service 74cec8
  $module =~ s/::$//;
Packit Service 74cec8
Packit Service 74cec8
  my $oldver = $require_removable{$module};
Packit Service 74cec8
  if ($oldver) {
Packit Service 74cec8
    $require_removable{$module} = $newver
Packit Service 74cec8
      if ($HAVE_VERSION && $newver && version->new($oldver) < $newver);
Packit Service 74cec8
  }
Packit Service 74cec8
  else {
Packit Service 74cec8
    $require_removable{$module} = $newver;
Packit Service 74cec8
  }
Packit Service 74cec8
}
Packit Service 74cec8
Packit 745a47
sub process_file {
Packit 745a47
Packit 745a47
  my ($file) = @_;
Packit 745a47
  chomp $file;
Packit 745a47
Packit 745a47
  if (!open(FILE, $file)) {
Packit 745a47
    warn("$0: Warning: Could not open file '$file' for reading: $!\n");
Packit 745a47
    return;
Packit 745a47
  }
Packit 745a47
Packit 745a47
  while (<FILE>) {
Packit 745a47
Packit 745a47
    # skip the here-docs "<<" blocks
Packit 745a47
    # assume that <<12 means bitwise operation
Packit 745a47
    if (((m/^\s*(?:'[^']*?'|"[^"]*?"|[^"'#]*?)*?[^"'#<@]<<[\\]?(\w+)\s*/ &&
Packit 745a47
          ($1 !~ m/^\d+$/)) ||
Packit 745a47
         m/^\s*(?:'[^']*?'|"[^"]*?"|[^"'#]*?)*?[^"'#<@]<<\s*('[^']*?'|"[^"]*?"|`[^`]*?`)\s*/
Packit 745a47
        ) &&
Packit 745a47
         ! m/q[qxwr]?\s*[{([#|!\/][^})\]#|!\/]*?<<[^<]/
Packit 745a47
       ) {
Packit 745a47
      $tag = $1;
Packit 745a47
      $tag =~ s/['"`]//g;
Packit 745a47
      if ($_ =~ m/^\s*use\s(constant)\s/) { add_require($1, undef) }
Packit 745a47
      while (<FILE>) {
Packit 745a47
        chomp;
Packit 745a47
        ( $_ eq $tag ) && last;
Packit 745a47
      }
Packit 745a47
      $_ = <FILE>;
Packit 745a47
    }
Packit 745a47
Packit 745a47
    # skip q{} quoted sections - just hope we don't have curly brackets
Packit 745a47
    # within the quote, nor an escaped hash mark that isn't a comment
Packit 745a47
    # marker, such as occurs right here. Draw the line somewhere.
Packit 745a47
    if ( m/^.*\Wq[qxwr]?\s*([{([#|!\/])[^})\]#|!\/]*$/ && ! m/^\s*(require|use)\s/ ) {
Packit 745a47
      $tag = $1;
Packit 745a47
      $tag =~ tr/{\(\[\#|!\//})]#|!\//;
Packit 745a47
      $tag = quotemeta($tag);
Packit 745a47
      while (<FILE>) {
Packit 745a47
        ( $_ =~ m/$tag/ ) && last;
Packit 745a47
      }
Packit 745a47
    }
Packit 745a47
Packit 745a47
    # skip the documentation
Packit 745a47
Packit 745a47
    # we should not need to have item in this if statement (it
Packit 745a47
    # properly belongs in the over/back section) but people do not
Packit 745a47
    # read the perldoc.
Packit 745a47
Packit 745a47
    if (/^=(head[1-4]|pod|for|item)/) {
Packit 745a47
      /^=cut/ && next while <FILE>;
Packit 745a47
    }
Packit 745a47
Packit 745a47
    if (/^=over/) {
Packit 745a47
      /^=back/ && next while <FILE>;
Packit 745a47
    }
Packit 745a47
Packit 745a47
    # skip the data section
Packit 745a47
    if (m/^__(DATA|END)__$/) {
Packit 745a47
      last;
Packit 745a47
    }
Packit 745a47
Packit 745a47
    # Each keyword can appear multiple times.  Don't
Packit 745a47
    #  bother with datastructures to store these strings,
Packit 745a47
    #  if we need to print it print it now.
Packit 745a47
    #
Packit 745a47
        # Again allow for "our".
Packit 745a47
    if (m/^\s*(our\s+)?\$RPM_Requires\s*=\s*["'](.*)['"]/i) {
Packit 745a47
      foreach $_ (split(/\s+/, $2)) {
Packit 745a47
        print "$_\n";
Packit 745a47
      }
Packit 745a47
    }
Packit 745a47
Packit 745a47
    my $modver_re = qr/[.0-9]+/;
Packit 745a47
    my $begin_re = qr#qw\s*[(\/'"!|{\[]\s*|qq?\s*[(\/'"!|{\[]\s*|['"]#;
Packit 745a47
    my $end_re   = qr#[)\/"'!|}\]]#;
Packit 745a47
Packit 745a47
    # Skip multiline print and assign statements
Packit 745a47
    if ( m/\$\S+\s*=\s*(")([^"\\]|(\\.))*$/ ||
Packit 745a47
         m/\$\S+\s*=\s*(')([^'\\]|(\\.))*$/ ||
Packit 745a47
         m/print\s+(")([^"\\]|(\\.))*$/ ||
Packit 745a47
         m/print\s+(')([^'\\]|(\\.))*$/ ) {
Packit 745a47
Packit 745a47
        my $quote = $1;
Packit 745a47
        while (<FILE>) {
Packit 745a47
          m/^([^\\$quote]|(\\.))*$quote/ && last;
Packit 745a47
        }
Packit 745a47
        $_ = <FILE>;
Packit 745a47
    }
Packit 745a47
Packit 745a47
    if (
Packit 745a47
Packit 745a47
# ouch could be in a eval, perhaps we do not want these since we catch
Packit 745a47
# an exception they must not be required
Packit 745a47
Packit 745a47
#   eval { require Term::ReadLine } or die $@;
Packit 745a47
#   eval "require Term::Rendezvous;" or die $@;
Packit 745a47
#   eval { require Carp } if defined $^S; # If error/warning during compilation,
Packit 745a47
Packit 745a47
Packit 745a47
        (m/^(\s*)         # we hope the inclusion starts the line
Packit 745a47
         (require|use)\s+(?!\{)     # do not want 'do {' loops
Packit 745a47
         # quotes around name are always legal
Packit 745a47
         (?:$begin_re?\s*([\w:\/\.]+?)\s*$end_re?|
Packit 745a47
            ([\w:\.]+?))[^\w]*?
Packit 745a47
         [\t; \n]
Packit 745a47
         # the syntax for 'use' allows version requirements
Packit 745a47
         \s*($modver_re)?\s*
Packit 745a47
         # catch parameter like '-norequire,'
Packit 745a47
         (-[\w,]+)?\s*
Packit 745a47
         # the latter part is for "use base qw(Foo)" and friends special case
Packit 745a47
         (?:$begin_re\s*
Packit 745a47
          ([^)\/"'\$!|}]*?)
Packit 745a47
          \s*$end_re|
Packit 745a47
          (?:qw<|qq?<)([^>]*?)>|([\w\:]+)|)\s*(.*)
Packit 745a47
         /x)
Packit 745a47
       ) {
Packit 745a47
      my ($whitespace, $statement, $module, $version, $params, $list, $rest) = ($1, $2, $3, $5, $6, $7 || $8 || $9, $10);
Packit 745a47
      $version = undef if ($version eq '');
Packit 745a47
Packit 745a47
      # Ignore line which contains direct method calls
Packit 745a47
      # use base __PACKAGE__->subroutine(...);
Packit 745a47
      $list = "" if ($list =~ /^[^;#]*?->/ || $rest =~ /^[^;#]*?->/);
Packit 745a47
Packit 745a47
      #
Packit 745a47
      # Executed in case that multiline q{} quoted sections is used for
Packit 745a47
      # list of modules
Packit 745a47
      if (defined($list) && $list =~ /^q[qxwr]?$/) {
Packit 745a47
        $list = "";
Packit 745a47
        if ($rest =~ m/^\s*([{([#|!\/])\s*([^})\]#|!\/]*)$/) {
Packit 745a47
          $tag  = $1;
Packit 745a47
          $list = $2;
Packit 745a47
          chomp($list);
Packit 745a47
          $tag  =~ tr/{\(\[\#|!\//})]#|!\//;
Packit 745a47
          $tag  = quotemeta($tag);
Packit 745a47
          while (<FILE>) {
Packit 745a47
            my $line = $_;
Packit 745a47
            chomp($line);
Packit 745a47
            if ($line =~ m/^\s*(.*?)$tag/) {
Packit 745a47
              $list .= ' ' . $1 if ($1 ne '');
Packit 745a47
              last;
Packit 745a47
            } else { $list .= ' ' . $line; }
Packit 745a47
          }
Packit 745a47
        }
Packit 745a47
      }
Packit 745a47
Packit 745a47
      # we only consider require statements that are flushed against
Packit 745a47
      # the left edge. any other require statements give too many
Packit 745a47
      # false positives, as they are usually inside of an if statement
Packit 745a47
      # as a fallback module or a rarely used option
Packit 745a47
Packit 745a47
      ($whitespace ne "" && $statement eq "require") && next;
Packit 745a47
Packit 745a47
      # if there is some interpolation of variables just skip this
Packit 745a47
      # dependency, we do not want
Packit 745a47
      #        do "$ENV{LOGDIR}/$rcfile";
Packit 745a47
Packit 745a47
      ($module =~ m/\$/) && next;
Packit 745a47
Packit 745a47
      # ignore variables
Packit 745a47
      ($module =~ m/^\s*[\$%@\*]/) && next;
Packit 745a47
Packit 745a47
      # skip if the phrase was "use of" -- shows up in gimp-perl, et al.
Packit 745a47
      next if $module eq 'of';
Packit 745a47
Packit 745a47
      # if the module ends in a comma we probably caught some
Packit 745a47
      # documentation of the form 'check stuff,\n do stuff, clean
Packit 745a47
      # stuff.' there are several of these in the perl distribution
Packit 745a47
Packit 745a47
      ($module  =~ m/[,>]$/) && next;
Packit 745a47
Packit 745a47
      # if the module name starts in a dot it is not a module name.
Packit 745a47
      # Is this necessary?  Please give me an example if you turn this
Packit 745a47
      # back on.
Packit 745a47
Packit 745a47
      #      ($module =~ m/^\./) && next;
Packit 745a47
Packit 745a47
      # if the module starts with /, it is an absolute path to a file
Packit 745a47
      if ($module =~ m(^/)) {
Packit 745a47
        print "$module\n";
Packit 745a47
        next;
Packit 745a47
      }
Packit 745a47
Packit 745a47
      # sometimes people do use POSIX qw(foo), or use POSIX(qw(foo)) etc.
Packit 745a47
      # we can strip qw.*$, as well as (.*$:
Packit 745a47
      $module =~ s/qw.*$//;
Packit 745a47
      $module =~ s/\(.*$//;
Packit 745a47
Packit 745a47
      # if the module ends with .pm, strip it to leave only basename.
Packit 745a47
      # .pm files are not accepted by 'use'
Packit 745a47
      ($module =~ s/\.pm$// && $statement eq 'use' ) && next;
Packit 745a47
Packit 745a47
      # some perl programmers write 'require URI/URL;' when
Packit 745a47
      # they mean 'require URI::URL;'
Packit 745a47
Packit 745a47
      ($module =~ s/\//::/ && $statement eq 'use' ) && next;
Packit 745a47
Packit 745a47
      # trim off trailing parentheses if any.  Sometimes people pass
Packit 745a47
      # the module an empty list.
Packit 745a47
Packit 745a47
      $module =~ s/\(\s*\)$//;
Packit 745a47
Packit 745a47
      if ( $module =~ m/^(v?[0-9._]+)$/ ) {
Packit 745a47
        # if module is a number then both require and use interpret that
Packit 745a47
        # to mean that a particular version of perl is specified
Packit 745a47
Packit 745a47
        my $rpm_ver = Fedora::VSP::vsp($1);
Packit 745a47
        if (defined $rpm_ver) {
Packit 745a47
          $perlreq{"$rpm_ver"} = 1;
Packit 745a47
          next;
Packit 745a47
        }
Packit 745a47
Packit 745a47
      };
Packit 745a47
Packit 745a47
      # ph files do not use the package name inside the file.
Packit 745a47
      # perlmodlib documentation says:
Packit 745a47
Packit 745a47
      #       the .ph files made by h2ph will probably end up as
Packit 745a47
      #       extension modules made by h2xs.
Packit 745a47
Packit 745a47
      # so do not expend much effort on these.
Packit 745a47
Packit 745a47
Packit 745a47
      # there is no easy way to find out if a file named systeminfo.ph
Packit 745a47
      # will be included with the name sys/systeminfo.ph so only use the
Packit 745a47
      # basename of *.ph files
Packit 745a47
Packit 745a47
      ($module =~ m/\.ph$/) && next;
Packit 745a47
Packit 745a47
      # use base|parent qw(Foo) dependencies
Packit 745a47
      # use aliased qw(Foo::Bar) dependencies
Packit Service 74cec8
      if ($statement eq "use" && $module eq "base") {
Packit Service 74cec8
        add_require($module, $version);
Packit Service 74cec8
        if (defined($list) && $list ne "") {
Packit Service 74cec8
          add_require_removable($_, undef) for split(' ', $list);
Packit Service 74cec8
        }
Packit Service 74cec8
        next;
Packit Service 74cec8
      }
Packit Service 74cec8
      if ($statement eq "use" && $module eq "aliased") {
Packit 745a47
        add_require($module, $version);
Packit 745a47
        if (defined($list) && $list ne "") {
Packit 745a47
          add_require($_, undef) for split(' ', $list);
Packit 745a47
        }
Packit 745a47
        next;
Packit 745a47
      }
Packit 745a47
      if ($statement eq "use" && $module eq "parent") {
Packit 745a47
        add_require($module, $version);
Packit 745a47
        if (defined($list) && $list ne "" && $params !~ /-norequire/) {
Packit 745a47
          add_require($_, undef) for split(' ', $list);
Packit 745a47
        }
Packit 745a47
        next;
Packit 745a47
      }
Packit 745a47
Packit 745a47
      # use Any::Moose dependencies
Packit 745a47
      # Mouse or Mouse::Role will be added
Packit 745a47
      if ($statement eq "use" && $module eq "Any::Moose") {
Packit 745a47
        add_require($module, $version);
Packit 745a47
        if (defined($list) && $list ne "") {
Packit 745a47
          if (grep { !/^Role$/ } split(' ', $list)) {
Packit 745a47
            add_require('Mouse::Role', undef);
Packit 745a47
          } else {
Packit 745a47
            add_require('Mouse', undef);
Packit 745a47
          }
Packit 745a47
        } else {
Packit 745a47
          add_require('Mouse', undef);
Packit 745a47
        }
Packit 745a47
        next;
Packit 745a47
      }
Packit 745a47
Packit 745a47
      add_require($module, $version);
Packit 745a47
    } # use|require regex
Packit 745a47
Packit 745a47
  } # while (<FILE>)
Packit 745a47
Packit 745a47
  close(FILE) ||
Packit 745a47
    die("$0: Could not close file: '$file' : $!\n");
Packit 745a47
Packit 745a47
  return;
Packit 745a47
}
Packit Service 74cec8
Packit Service 74cec8
sub process_file_provides {
Packit Service 74cec8
Packit Service 74cec8
  my ($file) = @_;
Packit Service 74cec8
  chomp $file;
Packit Service 74cec8
Packit Service 74cec8
  return if (! $HAVE_PROV);
Packit Service 74cec8
Packit Service 74cec8
  my @result = readpipe( "$prov_script $file" );
Packit Service 74cec8
  foreach my $prov (@result) {
Packit Service 74cec8
    $provide{$1} = undef if $prov =~ /perl\(([_:a-zA-Z0-9]+)\)/;
Packit Service 74cec8
  }
Packit Service 74cec8
Packit Service 74cec8
}